input.c 101 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

Laurent Aimar's avatar
Laurent Aimar committed
38
#include "input_internal.h"
39
#include "es_out.h"
40

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

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

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

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

58 59
static  void* Run            ( vlc_object_t *p_this );
static  void* RunAndDestroy  ( vlc_object_t *p_this );
Laurent Aimar's avatar
Laurent Aimar committed
60

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

68
static inline int ControlPopNoLock( input_thread_t *, int *, vlc_value_t *, mtime_t i_deadline );
Laurent Aimar's avatar
Laurent Aimar committed
69
static void       ControlReduce( input_thread_t * );
70
static bool Control( input_thread_t *, int, vlc_value_t );
71

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

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

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

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

88 89
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 );
90 91
static char *InputGetExtraFiles( input_thread_t *p_input,
                                 const char *psz_access, const char *psz_path );
92

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
static void SubtitleAdd( input_thread_t *p_input, char *psz_subtitle, bool b_forced );

100
/*****************************************************************************
101 102
 * 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
103 104 105 106 107 108 109 110 111 112
 *
 * 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
113
 *  - audio-delay, spu-delay
Laurent Aimar's avatar
Laurent Aimar committed
114 115 116 117
 *  - bookmark
 * * Get only:
 *  - length
 *  - bookmarks
118 119
 *  - seekable (if you can seek, it doesn't say if 'bar display' has be shown
 *    or not, for that check position != 0.0)
120
 *  - can-pause
121
 *  - can-record (if a stream can be recorded while playing)
122
 *  - teletext-es to get the index of spu track that is teletext --1 if no teletext)
123
 * * For intf callback upon changes:
Laurent Aimar's avatar
Laurent Aimar committed
124
 *  - intf-change
125
 *  - intf-change-vout for when a vout is created or destroyed
126
 *  - rate-change for when playback rate changes
127
 *  - stats-change for when statistics are updated
Laurent Aimar's avatar
Laurent Aimar committed
128 129
 * TODO explain when Callback is called
 * TODO complete this list (?)
130
 *****************************************************************************/
131
static input_thread_t *Create( vlc_object_t *p_parent, input_item_t *p_item,
132
                               const char *psz_header, bool b_quick,
133
                               sout_instance_t *p_sout )
Michel Kaempf's avatar
Michel Kaempf committed
134
{
135
    static const char input_name[] = "input";
136
    input_thread_t *p_input = NULL;                 /* thread descriptor */
137 138
    vlc_value_t val;
    int i;
139

140
    /* Allocate descriptor */
141 142
    p_input = vlc_custom_create( p_parent, sizeof( *p_input ),
                                 VLC_OBJECT_INPUT, input_name );
143
    if( p_input == NULL )
144
        return NULL;
145 146 147 148 149 150

    /* 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 );
151 152 153

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

154 155 156 157 158 159 160
    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 );

Clément Stenac's avatar
Clément Stenac committed
161
    MALLOC_NULL( p_input->p, input_thread_private_t );
Rafaël Carré's avatar
Rafaël Carré committed
162
    memset( p_input->p, 0, sizeof( input_thread_private_t ) );
163 164 165

    /* One "randomly" selected input thread is responsible for computing
     * the global stats. Check if there is already someone doing this */
166
    if( p_input->p_libvlc->p_stats && !b_quick )
167
    {
168
        libvlc_priv_t *p_private = libvlc_priv( p_input->p_libvlc );
169
        vlc_mutex_lock( &p_input->p_libvlc->p_stats->lock );
170 171
        if( p_private->p_stats_computer == NULL )
            p_private->p_stats_computer = p_input;
172
        vlc_mutex_unlock( &p_input->p_libvlc->p_stats->lock );
173 174
    }

175
    p_input->b_preparsing = b_quick;
176
    p_input->psz_header = psz_header ? strdup( psz_header ) : NULL;
177

178
    /* Init events */
179 180 181
    vlc_event_manager_t * p_em = &p_input->p->event_manager;
    vlc_event_manager_init_with_vlc_object( p_em, p_input );
    vlc_event_manager_register_event_type( p_em, vlc_InputStateChanged );
182
    vlc_event_manager_register_event_type( p_em, vlc_InputSelectedStreamChanged );
183

Laurent Aimar's avatar
Laurent Aimar committed
184
    /* Init Common fields */
185 186
    p_input->b_eof = false;
    p_input->b_can_pace_control = true;
Clément Stenac's avatar
Clément Stenac committed
187
    p_input->p->i_start = 0;
Laurent Aimar's avatar
Laurent Aimar committed
188
    p_input->i_time  = 0;
Clément Stenac's avatar
Clément Stenac committed
189
    p_input->p->i_stop  = 0;
190
    p_input->p->i_run  = 0;
Clément Stenac's avatar
Clément Stenac committed
191 192 193
    p_input->p->i_title = 0;
    p_input->p->title   = NULL;
    p_input->p->i_title_offset = p_input->p->i_seekpoint_offset = 0;
Laurent Aimar's avatar
Laurent Aimar committed
194
    p_input->i_state = INIT_S;
Clément Stenac's avatar
Clément Stenac committed
195
    p_input->p->i_rate  = INPUT_RATE_DEFAULT;
196
    p_input->p->b_recording = false;
197 198
    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
199 200
    p_input->p->p_es_out = NULL;
    p_input->p->p_sout  = NULL;
201
    p_input->p->b_out_pace_control = false;
Laurent Aimar's avatar
Laurent Aimar committed
202 203 204
    p_input->i_pts_delay = 0;

    /* Init Input fields */
Pierre's avatar
Pierre committed
205
    vlc_gc_incref( p_item ); /* Released in Destructor() */
Clément Stenac's avatar
Clément Stenac committed
206 207 208 209
    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;
210
    p_input->p->input.b_title_demux = false;
Clément Stenac's avatar
Clément Stenac committed
211 212 213
    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;
214 215 216 217
    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
218 219
    p_input->p->input.i_cr_average = 0;

220
    vlc_mutex_lock( &p_item->lock );
221 222

    if( !p_item->p_stats )
223 224
        p_item->p_stats = stats_NewInputStats( p_input );
    vlc_mutex_unlock( &p_item->lock );
Clément Stenac's avatar
Clément Stenac committed
225

226
    /* No slave */
Clément Stenac's avatar
Clément Stenac committed
227 228
    p_input->p->i_slave = 0;
    p_input->p->slave   = NULL;
229

Laurent Aimar's avatar
Laurent Aimar committed
230
    /* Init control buffer */
231
    vlc_mutex_init( &p_input->p->lock_control );
232
    vlc_cond_init( &p_input->p->wait_control );
Clément Stenac's avatar
Clément Stenac committed
233
    p_input->p->i_control = 0;
234

Gildas Bazin's avatar
 
Gildas Bazin committed
235
    /* Parse input options */
236
    vlc_mutex_lock( &p_item->lock );
Pierre d'Herbemont's avatar
Pierre d'Herbemont committed
237
    assert( (int)p_item->optflagc == p_item->i_options );
238
    for( i = 0; i < p_item->i_options; i++ )
239 240
        var_OptionParse( VLC_OBJECT(p_input), p_item->ppsz_options[i],
                         !!(p_item->optflagv[i] & VLC_INPUT_OPTION_TRUSTED) );
241
    vlc_mutex_unlock( &p_item->lock );
Gildas Bazin's avatar
 
Gildas Bazin committed
242

Laurent Aimar's avatar
Laurent Aimar committed
243 244
    /* Create Object Variables for private use only */
    input_ConfigVarInit( p_input );
Michel Kaempf's avatar
Michel Kaempf committed
245

Laurent Aimar's avatar
Laurent Aimar committed
246
    /* Create Objects variables for public Get and Set */
247
    input_ControlVarInit( p_input );
248

249
    /* */
Clément Stenac's avatar
Clément Stenac committed
250
    p_input->p->input.i_cr_average = var_GetInteger( p_input, "cr-average" );
Gildas Bazin's avatar
Gildas Bazin committed
251

252
    if( !p_input->b_preparsing )
Gildas Bazin's avatar
Gildas Bazin committed
253
    {
254 255
        var_Get( p_input, "bookmarks", &val );
        if( val.psz_string )
Gildas Bazin's avatar
Gildas Bazin committed
256
        {
257 258 259 260
            /* 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
261
            {
262
                 seekpoint_t *p_seekpoint;
263 264 265 266 267 268 269 270
                 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 = ',';
271 272

                 p_seekpoint = vlc_seekpoint_New();
273 274 275 276 277
                 while( (psz_end = strchr( psz_start, ',' ) ) )
                 {
                     *psz_end = 0;
                     if( !strncmp( psz_start, "name=", 5 ) )
                     {
278
                         p_seekpoint->psz_name = strdup(psz_start + 5);
279 280 281 282 283 284 285
                     }
                     else if( !strncmp( psz_start, "bytes=", 6 ) )
                     {
                         p_seekpoint->i_byte_offset = atoll(psz_start + 6);
                     }
                     else if( !strncmp( psz_start, "time=", 5 ) )
                     {
286 287
                         p_seekpoint->i_time_offset = atoll(psz_start + 5) *
                                                        1000000;
288 289
                     }
                     psz_start = psz_end + 1;
Gildas Bazin's avatar
Gildas Bazin committed
290
                }
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
291
                msg_Dbg( p_input, "adding bookmark: %s, bytes=%"PRId64", time=%"PRId64,
292 293 294 295 296
                                  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
297
            }
298
            free( val.psz_string );
Gildas Bazin's avatar
Gildas Bazin committed
299 300 301
        }
    }

302
    /* Remove 'Now playing' info as it is probably outdated */
303
    input_item_SetNowPlaying( p_item, NULL );
304

305 306 307 308
    /* */
    if( p_input->b_preparsing )
        p_input->i_flags |= OBJECT_FLAGS_QUIET | OBJECT_FLAGS_NOINTERACT;

309 310 311 312
    /* */
    if( p_sout )
        p_input->p->p_sout = p_sout;

313
    memset( &p_input->p->counters, 0, sizeof( p_input->p->counters ) );
314
    vlc_mutex_init( &p_input->p->counters.counters_lock );
315

316 317 318
    /* Set the destructor when we are sure we are initialized */
    vlc_object_set_destructor( p_input, (vlc_destructor_t)Destructor );

319 320 321
    /* Attach only once we are ready */
    vlc_object_attach( p_input, p_parent );

322 323 324
    return p_input;
}

325 326 327 328
/**
 * Input destructor (called when the object's refcount reaches 0).
 */
static void Destructor( input_thread_t * p_input )
329
{
330 331 332 333 334 335
#ifndef NDEBUG
    char * psz_name = input_item_GetName( p_input->p->input.p_item );
    msg_Dbg( p_input, "Destroying the input for '%s'", psz_name);
    free( psz_name );
#endif

336 337
    vlc_event_manager_fini( &p_input->p->event_manager );

338 339
    stats_TimerDump( p_input, STATS_TIMER_INPUT_LAUNCHING );
    stats_TimerClean( p_input, STATS_TIMER_INPUT_LAUNCHING );
340
#ifdef ENABLE_SOUT
341 342
    if( p_input->p->p_sout )
        sout_DeleteInstance( p_input->p->p_sout );
343
#endif
Pierre's avatar
Pierre committed
344 345
    vlc_gc_decref( p_input->p->input.p_item );

346 347
    vlc_mutex_destroy( &p_input->p->counters.counters_lock );

348
    vlc_cond_destroy( &p_input->p->wait_control );
349 350
    vlc_mutex_destroy( &p_input->p->lock_control );
    free( p_input->p );
351
}
352

353
/**
354 355
 * Initialize an input thread and run it. You will need to monitor the
 * thread to clean up after it is done
356 357 358 359 360 361 362
 *
 * \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 )
363
{
364
    return __input_CreateThreadExtended( p_parent, p_item, NULL, NULL );
365 366
}

367 368 369 370
/* */
input_thread_t *__input_CreateThreadExtended( vlc_object_t *p_parent,
                                              input_item_t *p_item,
                                              const char *psz_log, sout_instance_t *p_sout )
371
{
372
    input_thread_t *p_input;
373

374
    p_input = Create( p_parent, p_item, psz_log, false, p_sout );
375 376 377
    if( !p_input )
        return NULL;

Sam Hocevar's avatar
Sam Hocevar committed
378
    /* Create thread and wait for its readiness. */
Laurent Aimar's avatar
Laurent Aimar committed
379
    if( vlc_thread_create( p_input, "input", Run,
380
                           VLC_THREAD_PRIORITY_INPUT, false ) )
Michel Kaempf's avatar
Michel Kaempf committed
381
    {
382
        input_ChangeState( p_input, ERROR_S );
383
        msg_Err( p_input, "cannot create input thread" );
384 385
        vlc_object_detach( p_input );
        vlc_object_release( p_input );
386
        return NULL;
Michel Kaempf's avatar
Michel Kaempf committed
387
    }
388

389
    return p_input;
Michel Kaempf's avatar
Michel Kaempf committed
390 391
}

392
/**
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
393
 * Initialize an input thread and run it. This thread will clean after itself,
394 395 396 397 398
 * 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 ?
399
 * \return an error code, VLC_SUCCESS on success
400
 */
401
int __input_Read( vlc_object_t *p_parent, input_item_t *p_item,
402
                   bool b_block )
403
{
404
    input_thread_t *p_input;
405

406
    p_input = Create( p_parent, p_item, NULL, false, NULL );
407
    if( !p_input )
408 409
        return VLC_EGENERIC;

410
    if( b_block )
411
    {
412
        RunAndDestroy( VLC_OBJECT(p_input) );
Clément Stenac's avatar
Clément Stenac committed
413
        return VLC_SUCCESS;
414
    }
415
    else
416
    {
417
        if( vlc_thread_create( p_input, "input", RunAndDestroy,
418
                               VLC_THREAD_PRIORITY_INPUT, false ) )
419
        {
420
            input_ChangeState( p_input, ERROR_S );
421
            msg_Err( p_input, "cannot create input thread" );
422
            vlc_object_release( p_input );
Clément Stenac's avatar
Clément Stenac committed
423
            return VLC_EGENERIC;
424
        }
425
    }
426
    return VLC_SUCCESS;
427
}
428

429 430 431 432 433 434 435 436 437 438
/**
 * 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 )
{
439
    input_thread_t *p_input;
440

441
    /* Allocate descriptor */
442
    p_input = Create( p_parent, p_item, NULL, true, NULL );
443 444 445
    if( !p_input )
        return VLC_EGENERIC;

446 447
    if( !Init( p_input ) )
        End( p_input );
448

449 450
    vlc_object_detach( p_input );
    vlc_object_release( p_input );
451 452 453 454

    return VLC_SUCCESS;
}

455 456 457 458 459
/**
 * Request a running input thread to stop and die
 *
 * \param the input thread to stop
 */
460
static void ObjectKillChildrens( input_thread_t *p_input, vlc_object_t *p_obj )
Michel Kaempf's avatar
Michel Kaempf committed
461
{
Laurent Aimar's avatar
Laurent Aimar committed
462 463
    vlc_list_t *p_list;
    int i;
464 465 466 467 468 469

    if( p_obj->i_object_type == VLC_OBJECT_VOUT ||
        p_obj->i_object_type == VLC_OBJECT_AOUT ||
        p_obj == VLC_OBJECT(p_input->p->p_sout) )
        return;

470
    vlc_object_kill( p_obj );
471

472
    p_list = vlc_list_children( p_obj );
Laurent Aimar's avatar
Laurent Aimar committed
473
    for( i = 0; i < p_list->i_count; i++ )
474
        ObjectKillChildrens( p_input, p_list->p_values[i].p_object );
Laurent Aimar's avatar
Laurent Aimar committed
475
    vlc_list_release( p_list );
476 477 478 479 480 481
}
void input_StopThread( input_thread_t *p_input )
{
    /* 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 */
482
    ObjectKillChildrens( p_input, VLC_OBJECT(p_input) );
Michel Kaempf's avatar
Michel Kaempf committed
483

Laurent Aimar's avatar
Laurent Aimar committed
484
    input_ControlPush( p_input, INPUT_CONTROL_SET_DIE, NULL );
Sam Hocevar's avatar
 
Sam Hocevar committed
485 486
}

487 488
sout_instance_t * input_DetachSout( input_thread_t *p_input )
{
489 490 491 492
    sout_instance_t *p_sout = p_input->p->p_sout;
    vlc_object_detach( p_sout );
    p_input->p->p_sout = NULL;
    return p_sout;
493 494
}

495
/*****************************************************************************
Laurent Aimar's avatar
Laurent Aimar committed
496
 * Run: main thread loop
497 498
 * This is the "normal" thread that spawns the input processing chain,
 * reads the stream, cleans up and waits
499
 *****************************************************************************/
500
static void* Run( vlc_object_t *p_this )
Michel Kaempf's avatar
Michel Kaempf committed
501
{
502
    input_thread_t *p_input = (input_thread_t *)p_this;
503
    const int canc = vlc_savecancel();
504

505
    if( Init( p_input ) )
Sam Hocevar's avatar
 
Sam Hocevar committed
506 507
    {
        /* If we failed, wait before we are killed, and exit */
508
        WaitDie( p_input );
509
        goto exit;
Sam Hocevar's avatar
 
Sam Hocevar committed
510
    }
Michel Kaempf's avatar
Michel Kaempf committed
511

512 513
    MainLoop( p_input );

514
    /* Wait until we are asked to die */
515
    if( !p_input->b_die )
516
        WaitDie( p_input );
517 518 519

    /* Clean up */
    End( p_input );
520 521 522

exit:
    p_input->b_dead = true;
523
    vlc_restorecancel( canc );
524
    return NULL;
525 526 527
}

/*****************************************************************************
528
 * RunAndDestroy: main thread loop
529 530 531
 * This is the "just forget me" thread that spawns the input processing chain,
 * reads the stream, cleans up and releases memory
 *****************************************************************************/
532
static void* RunAndDestroy( vlc_object_t *p_this )
533
{
534
    input_thread_t *p_input = (input_thread_t *)p_this;
535
    const int canc = vlc_savecancel();
536

537
    if( Init( p_input ) )
538
        goto exit;
539 540 541 542 543 544

    MainLoop( p_input );

    /* Clean up */
    End( p_input );

545
exit:
546
    /* Release memory */
547
    vlc_object_release( p_input );
548 549
    vlc_restorecancel( canc );
    return NULL;
550 551 552 553 554
}

/*****************************************************************************
 * Main loop: Fill buffers from access, and demux
 *****************************************************************************/
555 556 557 558 559 560

/**
 * MainLoopDemux
 * It asks the demuxer to demux some data
 */
static void MainLoopDemux( input_thread_t *p_input, bool *pb_changed, mtime_t *pi_start_mdate )
561
{
562
    int i_ret;
563

564
    *pb_changed = false;
565

566 567 568 569 570 571 572
    if( ( p_input->p->i_stop > 0 && p_input->i_time >= p_input->p->i_stop ) ||
        ( p_input->p->i_run > 0 && *pi_start_mdate+p_input->p->i_run < mdate() ) )
        i_ret = 0; /* EOF */
    else
        i_ret = p_input->p->input.p_demux->pf_demux(p_input->p->input.p_demux);

    if( i_ret > 0 )
Sam Hocevar's avatar
 
Sam Hocevar committed
573
    {
574 575 576 577 578 579 580 581 582 583 584 585 586 587 588
        /* TODO */
        if( p_input->p->input.b_title_demux &&
            p_input->p->input.p_demux->info.i_update )
        {
            i_ret = UpdateFromDemux( p_input );
            *pb_changed = true;
        }
        else if( !p_input->p->input.b_title_demux &&
                  p_input->p->input.p_access &&
                  p_input->p->input.p_access->info.i_update )
        {
            i_ret = UpdateFromAccess( p_input );
            *pb_changed = true;
        }
    }
589

590 591 592 593 594 595
    if( i_ret == 0 )    /* EOF */
    {
        vlc_value_t repeat;

        var_Get( p_input, "input-repeat", &repeat );
        if( repeat.i_int == 0 )
596
        {
597 598 599 600 601 602 603 604
            /* End of file - we do not set b_die because only the
             * playlist is allowed to do so. */
            msg_Dbg( p_input, "EOF reached" );
            p_input->p->input.b_eof = true;
        }
        else
        {
            vlc_value_t val;
605

606 607 608
            msg_Dbg( p_input, "repeating the same input (%d)",
                     repeat.i_int );
            if( repeat.i_int > 0 )
Laurent Aimar's avatar
Laurent Aimar committed
609
            {
610 611
                repeat.i_int--;
                var_Set( p_input, "input-repeat", repeat );
Laurent Aimar's avatar
Laurent Aimar committed
612
            }
613

614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629
            /* 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 )
Laurent Aimar's avatar
Laurent Aimar committed
630
            {
631 632 633
                val.i_time = p_input->p->i_start;
                input_ControlPush( p_input, INPUT_CONTROL_SET_TIME,
                                   &val );
634
            }
635
            else
Laurent Aimar's avatar
Laurent Aimar committed
636
            {
637 638 639
                val.f_float = 0.0;
                input_ControlPush( p_input, INPUT_CONTROL_SET_POSITION,
                                   &val );
Laurent Aimar's avatar
Laurent Aimar committed
640
            }
641

642 643 644 645 646 647 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 697 698 699 700 701 702 703 704 705 706 707 708 709 710
            /* */
            *pi_start_mdate = mdate();
        }
    }
    else if( i_ret < 0 )
    {
        input_ChangeState( p_input, ERROR_S );
    }

    if( i_ret > 0 && p_input->p->i_slave > 0 )
    {
        SlaveDemux( p_input );
    }
}

/**
 * MainLoopInterface
 * It update the variables used by the interfaces
 */
static void MainLoopInterface( input_thread_t *p_input )
{
    vlc_value_t val;
    double f_pos;
    int64_t i_time, i_length;

    /* update input status variables */
    if( !demux_Control( p_input->p->input.p_demux,
                         DEMUX_GET_POSITION, &f_pos ) )
    {
        val.f_float = (float)f_pos;
        var_Change( p_input, "position", VLC_VAR_SETVALUE, &val, NULL );
    }
    if( !demux_Control( p_input->p->input.p_demux,
                         DEMUX_GET_TIME, &i_time ) )
    {
        p_input->i_time = i_time;
        val.i_time = i_time;
        var_Change( p_input, "time", VLC_VAR_SETVALUE, &val, NULL );
    }
    if( !demux_Control( p_input->p->input.p_demux,
                         DEMUX_GET_LENGTH, &i_length ) )
    {
        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 );

        if( old_val.i_time != val.i_time )
        {
            UpdateItemLength( p_input, i_length );
        }
    }

    var_SetBool( p_input, "intf-change", true );
}

/**
 * MainLoopStatistic
 * It updates the globals statics
 */
static void MainLoopStatistic( input_thread_t *p_input )
{
    stats_ComputeInputStats( p_input, p_input->p->input.p_item->p_stats );
    /* Are we the thread responsible for computing global stats ? */
    if( libvlc_priv( p_input->p_libvlc )->p_stats_computer == p_input )
    {
        stats_ComputeGlobalStats( p_input->p_libvlc,
                                  p_input->p_libvlc->p_stats );
    }
711
    var_SetBool( p_input, "stats-change", true );
712 713 714 715 716 717 718 719 720
}

/**
 * MainLoop
 * The main input loop.
 */
static void MainLoop( input_thread_t *p_input )
{
    mtime_t i_start_mdate = mdate();
721 722
    mtime_t i_intf_update = 0;
    mtime_t i_statistic_update = 0;
723 724 725 726 727 728 729 730 731

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

    while( !p_input->b_die && !p_input->b_error && !p_input->p->input.b_eof )
    {
        bool b_force_update;
        int i_type;
        vlc_value_t val;
732
        mtime_t i_current;
733
        mtime_t i_deadline;
734
        mtime_t i_wakeup;
735
        bool b_paused;
736

737 738
        /* Demux data */
        b_force_update = false;
739
        i_wakeup = 0;
740 741 742 743
        b_paused = p_input->i_state == PAUSE_S &&
                   !input_EsOutIsBuffering( p_input->p->p_es_out );

        if( !b_paused )
744
        {
745
            MainLoopDemux( p_input, &b_force_update, &i_start_mdate );
746 747
            i_wakeup = input_EsOutGetWakeup( p_input->p->p_es_out );
        }
748 749

        /* */
750 751
        do {
            i_deadline = i_wakeup;
752
            if( b_paused )
753 754 755 756 757 758 759 760 761 762 763 764
                i_deadline = __MIN( i_intf_update, i_statistic_update );

            /* Handle control */
            vlc_mutex_lock( &p_input->p->lock_control );
            ControlReduce( p_input );
            while( !ControlPopNoLock( p_input, &i_type, &val, i_deadline ) )
            {
                msg_Dbg( p_input, "control type=%d", i_type );
                if( Control( p_input, i_type, val ) )
                    b_force_update = true;
            }
            vlc_mutex_unlock( &p_input->p->lock_control );
765

766 767 768 769 770 771 772 773 774 775 776 777 778
            /* 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);
            }
779 780 781 782 783 784 785 786

            /* Check if i_wakeup is still valid */
            if( i_wakeup != 0 )
            {
                mtime_t i_new_wakeup = input_EsOutGetWakeup( p_input->p->p_es_out );
                if( !i_new_wakeup )
                    i_wakeup = 0;
            }
787
        } while( i_current < i_wakeup );
Laurent Aimar's avatar
Laurent Aimar committed
788
    }
789 790 791 792

    if( !p_input->b_eof && !p_input->b_error && p_input->p->input.b_eof )
    {
        /* We have finish to demux data but not to play them */
793
        while( vlc_object_alive( p_input ) )
794
        {
795
            if( input_EsOutDecodersIsEmpty( p_input->p->p_es_out ) )
796 797 798 799 800 801 802 803 804 805
                break;

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

            msleep( INPUT_IDLE_SLEEP );
        }

        /* We have finished */
        input_ChangeState( p_input, END_S );
    }
806 807
}

808
static void InitStatistics( input_thread_t * p_input )
Michel Kaempf's avatar
Michel Kaempf committed
809
{
810
    if( p_input->b_preparsing ) return;
811

812 813 814
    /* Prepare statistics */
#define INIT_COUNTER( c, type, compute ) p_input->p->counters.p_##c = \
 stats_CounterCreate( p_input, VLC_VAR_##type, STATS_##compute);
815
    if( libvlc_stats( p_input ) )
816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835
    {
        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;
836
    }
837
}
838

839
#ifdef ENABLE_SOUT
840 841 842 843 844 845 846 847 848
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 ) )
849
    {
850 851
        /* Check the validity of the provided sout */
        if( p_input->p->p_sout )
Clément Stenac's avatar
Clément Stenac committed
852
        {
853
            if( strcmp( p_input->p->p_sout->psz_sout, psz ) )
854
            {
855
                msg_Dbg( p_input, "destroying unusable sout" );
856

857 858
                sout_DeleteInstance( p_input->p->p_sout );
                p_input->p->p_sout = NULL;
859
            }
860
        }
861

862 863 864 865 866 867 868 869 870 871 872 873 874
        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
875
            {
876 877 878 879 880
                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
881
            }
882
        }
883
        if( libvlc_stats( p_input ) )
884
        {
885
            INIT_COUNTER( sout_sent_packets, INTEGER, COUNTER );
886
            INIT_COUNTER( sout_sent_bytes, INTEGER, COUNTER );
887 888 889 890
            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;
891
        }
892
    }
893
    else if( p_input->p->p_sout )
894
    {