input.c 49.4 KB
Newer Older
1 2
/*****************************************************************************
 * input.c: input thread
3
 * Read a stream, demultiplex and parse it before sending it to
Michel Kaempf's avatar
Michel Kaempf committed
4
 * decoders.
5
 *****************************************************************************
6
 * Copyright (C) 1998-2004 VideoLAN
7
 * $Id$
8
 *
9
 * Authors: Christophe Massiot <massiot@via.ecp.fr>
10 11 12 13 14
 *
 * 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.
15
 *
16 17
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 19
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
20
 *
21 22 23
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
24
 *****************************************************************************/
Michel Kaempf's avatar
Michel Kaempf committed
25

26
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
27
 * Preamble
28
 *****************************************************************************/
29
#include <stdlib.h>
Sam Hocevar's avatar
 
Sam Hocevar committed
30

31
#include <vlc/vlc.h>
32
#include <vlc/input.h>
33
#include <vlc/decoder.h>
34
#include <vlc/vout.h>
Sam Hocevar's avatar
 
Sam Hocevar committed
35

36 37
#ifdef HAVE_SYS_TIMES_H
#   include <sys/times.h>
38
#endif
39

40 41
#include "stream_output.h"

42
#include "vlc_interface.h"
43
#include "codecs.h"
44
#include "vlc_meta.h"
45
#include "../../modules/demux/util/sub.h"
Sam Hocevar's avatar
 
Sam Hocevar committed
46

47
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
48
 * Local prototypes
49
 *****************************************************************************/
50 51 52 53 54
struct input_thread_sys_t
{
    /* subtitles */
    int              i_sub;
    subtitle_demux_t **sub;
55 56

    int64_t          i_stop_time;
57 58
};

59 60 61 62
static  int RunThread  ( input_thread_t *p_input );
static  int InitThread ( input_thread_t *p_input );
static void ErrorThread( input_thread_t *p_input );
static void EndThread  ( input_thread_t *p_input );
Michel Kaempf's avatar
Michel Kaempf committed
63

64 65 66
static void ParseOption( input_thread_t *p_input, const char *psz_option );

static void DecodeUrl  ( char * );
67

68 69 70 71 72 73 74 75 76 77 78
/*****************************************************************************
 * Callbacks
 *****************************************************************************/
static int PositionCallback( vlc_object_t *p_this, char const *psz_cmd,
                             vlc_value_t oldval, vlc_value_t newval, void *p_data );
static int TimeCallback    ( vlc_object_t *p_this, char const *psz_cmd,
                             vlc_value_t oldval, vlc_value_t newval, void *p_data );
static int StateCallback   ( vlc_object_t *p_this, char const *psz_cmd,
                             vlc_value_t oldval, vlc_value_t newval, void *p_data );
static int RateCallback    ( vlc_object_t *p_this, char const *psz_cmd,
                             vlc_value_t oldval, vlc_value_t newval, void *p_data );
Gildas Bazin's avatar
Gildas Bazin committed
79 80
static int BookmarkCallback( vlc_object_t *p_this, char const *psz_cmd,
                             vlc_value_t oldval, vlc_value_t newval, void *p_data );
Gildas Bazin's avatar
 
Gildas Bazin committed
81

82
/*****************************************************************************
83
 * input_CreateThread: creates a new input thread
84
 *****************************************************************************
85 86
 * This function creates a new input, and returns a pointer
 * to its description. On error, it returns NULL.
87
 *****************************************************************************/
88 89
input_thread_t *__input_CreateThread( vlc_object_t *p_parent,
                                      input_item_t *p_item )
90

Michel Kaempf's avatar
Michel Kaempf committed
91
{
92 93 94
    input_thread_t *p_input;                        /* thread descriptor */
    vlc_value_t     val;
    int             i;
95

96
    /* Allocate descriptor */
97
    p_input = vlc_object_create( p_parent, VLC_OBJECT_INPUT );
98
    if( p_input == NULL )
Michel Kaempf's avatar
Michel Kaempf committed
99
    {
100
        msg_Err( p_parent, "out of memory" );
101
        return NULL;
Michel Kaempf's avatar
Michel Kaempf committed
102
    }
103

104 105 106
    /* Store pointer to input item descriptor */
    p_input->p_item = p_item;

Gildas Bazin's avatar
 
Gildas Bazin committed
107
    /* Parse input options */
108 109
    vlc_mutex_lock( &p_item->lock );
    for( i = 0; i < p_item->i_options; i++ )
Gildas Bazin's avatar
 
Gildas Bazin committed
110
    {
111 112
        msg_Dbg( p_input, "option: %s", p_item->ppsz_options[i] );
        ParseOption( p_input, p_item->ppsz_options[i] );
Gildas Bazin's avatar
 
Gildas Bazin committed
113
    }
114
    vlc_mutex_unlock( &p_item->lock );
Gildas Bazin's avatar
 
Gildas Bazin committed
115

Gildas Bazin's avatar
 
Gildas Bazin committed
116 117 118 119 120
    /* Create a few object variables we'll need later on */
    var_Create( p_input, "video", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
    var_Create( p_input, "audio", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
    var_Create( p_input, "audio-channel", VLC_VAR_INTEGER|VLC_VAR_DOINHERIT );
    var_Create( p_input, "spu-channel", VLC_VAR_INTEGER|VLC_VAR_DOINHERIT );
121
    var_Create( p_input, "sub-file", VLC_VAR_FILE | VLC_VAR_DOINHERIT );
122 123 124 125
    var_Create( p_input, "sub-autodetect-file", VLC_VAR_BOOL |
                VLC_VAR_DOINHERIT );
    var_Create( p_input, "sub-autodetect-fuzzy", VLC_VAR_INTEGER |
                VLC_VAR_DOINHERIT );
Gildas Bazin's avatar
 
Gildas Bazin committed
126 127

    var_Create( p_input, "sout", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
128
    var_Create( p_input, "sout-all",   VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
Gildas Bazin's avatar
 
Gildas Bazin committed
129 130
    var_Create( p_input, "sout-audio", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
    var_Create( p_input, "sout-video", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
131 132
    var_Create( p_input, "sout-keep",  VLC_VAR_BOOL | VLC_VAR_DOINHERIT );

133 134 135
    /* repeat variable */
    var_Create( p_input, "input-repeat", VLC_VAR_INTEGER|VLC_VAR_DOINHERIT );

136 137 138 139
    /* start/stop time */
    var_Create( p_input, "start-time", VLC_VAR_INTEGER|VLC_VAR_DOINHERIT );
    var_Create( p_input, "stop-time", VLC_VAR_INTEGER|VLC_VAR_DOINHERIT );

140
    /* decoders */
Gildas Bazin's avatar
Gildas Bazin committed
141
    var_Create( p_input, "minimize-threads", VLC_VAR_BOOL|VLC_VAR_DOINHERIT );
142

143 144 145
    /* play status */

    /* position variable */
146 147
    var_Create( p_input, "position",  VLC_VAR_FLOAT );  /* position 0.0->1.0 */
    var_Create( p_input, "position-offset",  VLC_VAR_FLOAT );  /* relative */
148 149 150
    val.f_float = 0.0;
    var_Change( p_input, "position", VLC_VAR_SETVALUE, &val, NULL );
    var_AddCallback( p_input, "position", PositionCallback, NULL );
151
    var_AddCallback( p_input, "position-offset", PositionCallback, NULL );
152 153 154

    /* time variable */
    var_Create( p_input, "time",  VLC_VAR_TIME );
155
    var_Create( p_input, "time-offset",  VLC_VAR_TIME );    /* relative */
156 157 158
    val.i_time = 0;
    var_Change( p_input, "time", VLC_VAR_SETVALUE, &val, NULL );
    var_AddCallback( p_input, "time", TimeCallback, NULL );
159
    var_AddCallback( p_input, "time-offset", TimeCallback, NULL );
160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181

    /* length variable */
    var_Create( p_input, "length",  VLC_VAR_TIME );
    val.i_time = 0;
    var_Change( p_input, "length", VLC_VAR_SETVALUE, &val, NULL );

    /* rate variable */
    var_Create( p_input, "rate", VLC_VAR_INTEGER );
    var_Create( p_input, "rate-slower", VLC_VAR_VOID );
    var_Create( p_input, "rate-faster", VLC_VAR_VOID );
    val.i_int = DEFAULT_RATE;
    var_Change( p_input, "rate", VLC_VAR_SETVALUE, &val, NULL );
    var_AddCallback( p_input, "rate", RateCallback, NULL );
    var_AddCallback( p_input, "rate-slower", RateCallback, NULL );
    var_AddCallback( p_input, "rate-faster", RateCallback, NULL );

    /* state variable */
    var_Create( p_input, "state", VLC_VAR_INTEGER );
    val.i_int = INIT_S;
    var_Change( p_input, "state", VLC_VAR_SETVALUE, &val, NULL );
    var_AddCallback( p_input, "state", StateCallback, NULL );

182 183 184 185
    /* state variable */
    var_Create( p_input, "demuxed-id3", VLC_VAR_BOOL );
    val.b_bool = VLC_FALSE;
    var_Change( p_input, "demuxed-id3", VLC_VAR_SETVALUE, &val, NULL );
Gildas Bazin's avatar
 
Gildas Bazin committed
186

187
    /* Initialize thread properties */
Sam Hocevar's avatar
 
Sam Hocevar committed
188
    p_input->b_eof      = 0;
189
    p_input->b_out_pace_control = VLC_FALSE;
190
    p_input->p_sys      = NULL;
Sam Hocevar's avatar
 
Sam Hocevar committed
191 192

    /* Set target */
193 194 195
    vlc_mutex_lock( &p_item->lock );
    p_input->psz_source = strdup( p_item->psz_uri );
    vlc_mutex_unlock( &p_item->lock );
Sam Hocevar's avatar
 
Sam Hocevar committed
196

197 198 199
    /* Stream */
    p_input->s = NULL;

200 201 202
    /* es out */
    p_input->p_es_out = NULL;

Stéphane Borel's avatar
 
Stéphane Borel committed
203
    /* Demux */
204 205 206
    p_input->p_demux   = NULL;
    p_input->pf_demux  = NULL;
    p_input->pf_rewind = NULL;
Gildas Bazin's avatar
Gildas Bazin committed
207
    p_input->pf_demux_control = demux_vaControlDefault;
208
    p_input->i_cr_average = config_GetInt( p_input, "cr-average" );
Stéphane Borel's avatar
 
Stéphane Borel committed
209 210

    /* Access */
211
    p_input->p_access = NULL;
212

Sam Hocevar's avatar
 
Sam Hocevar committed
213 214
    p_input->i_bufsize = 0;
    p_input->i_mtu = 0;
Gildas Bazin's avatar
 
Gildas Bazin committed
215
    p_input->i_pts_delay = DEFAULT_PTS_DELAY;
Sam Hocevar's avatar
 
Sam Hocevar committed
216

217 218 219 220 221 222
    /* Initialize statistics */
    p_input->c_loops                    = 0;
    p_input->stream.c_packets_read      = 0;
    p_input->stream.c_packets_trashed   = 0;

    /* Set locks. */
223
    vlc_mutex_init( p_input, &p_input->stream.stream_lock );
224
    vlc_cond_init( p_input, &p_input->stream.stream_wait );
225
    vlc_mutex_init( p_input, &p_input->stream.control.control_lock );
Michel Kaempf's avatar
Michel Kaempf committed
226

227
    /* Initialize stream description */
Stéphane Borel's avatar
 
Stéphane Borel committed
228
    p_input->stream.b_changed = 0;
229 230
    p_input->stream.i_es_number = 0;
    p_input->stream.i_selected_es_number = 0;
231
    p_input->stream.i_pgrm_number = 0;
232
    p_input->stream.i_new_status = p_input->stream.i_new_rate = 0;
233
    p_input->stream.b_new_mute = MUTE_NO_CHANGE;
Christophe Massiot's avatar
Christophe Massiot committed
234
    p_input->stream.i_mux_rate = 0;
235
    p_input->stream.b_seekable = 0;
236
    p_input->stream.p_sout = NULL;
Michel Kaempf's avatar
Michel Kaempf committed
237

Sam Hocevar's avatar
 
Sam Hocevar committed
238 239 240
    /* no stream, no program, no area, no es */
    p_input->stream.p_new_program = NULL;

Stéphane Borel's avatar
 
Stéphane Borel committed
241 242
    p_input->stream.i_area_nb = 0;
    p_input->stream.pp_areas = NULL;
243
    p_input->stream.p_selected_area = NULL;
244
    p_input->stream.p_new_area = NULL;
Sam Hocevar's avatar
 
Sam Hocevar committed
245

Sam Hocevar's avatar
 
Sam Hocevar committed
246 247 248 249
    p_input->stream.pp_selected_es = NULL;
    p_input->stream.p_removed_es = NULL;
    p_input->stream.p_newly_selected_es = NULL;

Sam Hocevar's avatar
 
Sam Hocevar committed
250
    /* By default there is one area in a stream */
Gildas Bazin's avatar
 
Gildas Bazin committed
251
    input_AddArea( p_input, 0, 1 );
252
    p_input->stream.p_selected_area = p_input->stream.pp_areas[0];
Stéphane Borel's avatar
 
Stéphane Borel committed
253

254
    /* Initialize stream control properties. */
255
    p_input->stream.control.i_status = INIT_S;
256 257
    p_input->stream.control.i_rate = DEFAULT_RATE;
    p_input->stream.control.b_mute = 0;
Gildas Bazin's avatar
 
Gildas Bazin committed
258
    p_input->stream.control.b_grayscale = config_GetInt( p_input, "grayscale");
259

260
    msg_Info( p_input, "playlist item `%s'", p_input->psz_source );
Michel Kaempf's avatar
Michel Kaempf committed
261

Gildas Bazin's avatar
Gildas Bazin committed
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 300 301 302
    /* Bookmarks */
    var_Create( p_input, "bookmarks", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
    var_Create( p_input, "bookmark", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE |
                VLC_VAR_ISCOMMAND );
    val.psz_string = _("Bookmark");
    var_Change( p_input, "bookmark", VLC_VAR_SETTEXT, &val, NULL );
    var_AddCallback( p_input, "bookmark", BookmarkCallback, NULL );

    p_input->i_bookmarks = 0;
    p_input->pp_bookmarks = NULL;

    var_Get( p_input, "bookmarks", &val );
    if( val.psz_string )
    {
        /* 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, '{' ) ) )
        {
            seekpoint_t seekpoint;
            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 = ',';

            seekpoint.psz_name = 0;
            seekpoint.i_byte_offset = 0;
            seekpoint.i_time_offset = 0;
            while( (psz_end = strchr( psz_start, ',' ) ) )
            {
                *psz_end = 0;
                if( !strncmp( psz_start, "name=", 5 ) )
                {
                    seekpoint.psz_name = psz_start + 5;
                }
                else if( !strncmp( psz_start, "bytes=", 6 ) )
                {
303
                    seekpoint.i_byte_offset = atoll(psz_start + 6);
Gildas Bazin's avatar
Gildas Bazin committed
304 305 306
                }
                else if( !strncmp( psz_start, "time=", 5 ) )
                {
307
                    seekpoint.i_time_offset = atoll(psz_start + 5) * 1000000;
Gildas Bazin's avatar
Gildas Bazin committed
308 309 310 311 312 313 314 315 316 317 318 319
                }
                psz_start = psz_end + 1;
            }
            msg_Dbg( p_input, "adding bookmark: %s, bytes="I64Fd", time="I64Fd,
                     seekpoint.psz_name, seekpoint.i_byte_offset,
                     seekpoint.i_time_offset );
            input_Control( p_input, INPUT_ADD_BOOKMARK, &seekpoint );
            *psz_parser = backup;
        }
        free( val.psz_string );
    }

320
    vlc_object_attach( p_input, p_parent );
Sam Hocevar's avatar
 
Sam Hocevar committed
321

Sam Hocevar's avatar
Sam Hocevar committed
322
    /* Create thread and wait for its readiness. */
323 324
    if( vlc_thread_create( p_input, "input", RunThread,
                           VLC_THREAD_PRIORITY_INPUT, VLC_TRUE ) )
Michel Kaempf's avatar
Michel Kaempf committed
325
    {
326
        msg_Err( p_input, "cannot create input thread" );
Michel Kaempf's avatar
Michel Kaempf committed
327
        free( p_input );
328
        return NULL;
Michel Kaempf's avatar
Michel Kaempf committed
329
    }
330

331
    return p_input;
Michel Kaempf's avatar
Michel Kaempf committed
332 333
}

334
/*****************************************************************************
Sam Hocevar's avatar
 
Sam Hocevar committed
335
 * input_StopThread: mark an input thread as zombie
336
 *****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
337
 * This function should not return until the thread is effectively cancelled.
338
 *****************************************************************************/
Sam Hocevar's avatar
Sam Hocevar committed
339
void input_StopThread( input_thread_t *p_input )
Michel Kaempf's avatar
Michel Kaempf committed
340
{
Sam Hocevar's avatar
 
Sam Hocevar committed
341 342
    /* Make the thread exit from a possible vlc_cond_wait() */
    vlc_mutex_lock( &p_input->stream.stream_lock );
343 344
    /* Request thread destruction */
    p_input->b_die = 1;
Michel Kaempf's avatar
Michel Kaempf committed
345

346 347
    vlc_cond_signal( &p_input->stream.stream_wait );
    vlc_mutex_unlock( &p_input->stream.stream_lock );
Sam Hocevar's avatar
 
Sam Hocevar committed
348 349 350 351 352 353 354 355 356 357
}

/*****************************************************************************
 * input_DestroyThread: mark an input thread as zombie
 *****************************************************************************
 * This function should not return until the thread is effectively cancelled.
 *****************************************************************************/
void input_DestroyThread( input_thread_t *p_input )
{
    /* Join the thread */
358
    vlc_thread_join( p_input );
Sam Hocevar's avatar
 
Sam Hocevar committed
359 360 361

    /* Destroy Mutex locks */
    vlc_mutex_destroy( &p_input->stream.control.control_lock );
Sam Hocevar's avatar
 
Sam Hocevar committed
362
    vlc_cond_destroy( &p_input->stream.stream_wait );
Sam Hocevar's avatar
 
Sam Hocevar committed
363
    vlc_mutex_destroy( &p_input->stream.stream_lock );
Michel Kaempf's avatar
Michel Kaempf committed
364 365
}

366
/*****************************************************************************
367
 * RunThread: main thread loop
368
 *****************************************************************************
369
 * Thread in charge of processing the network packets and demultiplexing.
370
 *****************************************************************************/
Sam Hocevar's avatar
 
Sam Hocevar committed
371
static int RunThread( input_thread_t *p_input )
Michel Kaempf's avatar
Michel Kaempf committed
372
{
373 374 375
    vlc_value_t  val;
    mtime_t      i_update_next = -1;

Sam Hocevar's avatar
Sam Hocevar committed
376 377 378
    /* Signal right now, otherwise we'll get stuck in a peek */
    vlc_thread_ready( p_input );

Sam Hocevar's avatar
 
Sam Hocevar committed
379 380 381 382
    if( InitThread( p_input ) )
    {
        /* If we failed, wait before we are killed, and exit */
        p_input->b_error = 1;
383

Sam Hocevar's avatar
 
Sam Hocevar committed
384
        ErrorThread( p_input );
385 386 387 388

        /* Tell we're dead */
        p_input->b_dead = 1;

Sam Hocevar's avatar
 
Sam Hocevar committed
389
        return 0;
Sam Hocevar's avatar
 
Sam Hocevar committed
390
    }
Michel Kaempf's avatar
Michel Kaempf committed
391

392
    /* initialization is complete */
393
    vlc_mutex_lock( &p_input->stream.stream_lock );
394 395
    p_input->stream.b_changed        = 1;
    p_input->stream.control.i_status = PLAYING_S;
396 397
    vlc_mutex_unlock( &p_input->stream.stream_lock );

398 399 400
    val.i_int = PLAYING_S;
    var_Change( p_input, "state", VLC_VAR_SETVALUE, &val, NULL );

Sam Hocevar's avatar
 
Sam Hocevar committed
401 402
    while( !p_input->b_die && !p_input->b_error && !p_input->b_eof )
    {
403
        unsigned int i, i_count;
404

Sam Hocevar's avatar
 
Sam Hocevar committed
405
        p_input->c_loops++;
Sam Hocevar's avatar
 
Sam Hocevar committed
406

407
        vlc_mutex_lock( &p_input->stream.stream_lock );
408

409 410 411 412 413
        if( p_input->stream.p_new_program )
        {
            if( p_input->pf_set_program != NULL )
            {

Johan Bilien's avatar
 
Johan Bilien committed
414 415
                /* Reinitialize buffer manager. */
                input_AccessReinit( p_input );
416 417

                p_input->pf_set_program( p_input,
418
                                         p_input->stream.p_new_program );
419

420 421 422 423
                /* Escape all decoders for the stream discontinuity they
                 * will encounter. */
                input_EscapeDiscontinuity( p_input );

424 425 426 427 428 429 430 431 432 433 434
                for( i = 0; i < p_input->stream.i_pgrm_number; i++ )
                {
                    pgrm_descriptor_t * p_pgrm
                                            = p_input->stream.pp_programs[i];

                    /* Reinitialize synchro. */
                    p_pgrm->i_synchro_state = SYNCHRO_REINIT;
                }
            }
            p_input->stream.p_new_program = NULL;
        }
435

436 437
        if( p_input->stream.p_new_area )
        {
438 439
            if( p_input->stream.b_seekable && p_input->pf_set_area != NULL )
            {
440
                input_AccessReinit( p_input );
441 442 443

                p_input->pf_set_area( p_input, p_input->stream.p_new_area );

444 445 446 447
                /* Escape all decoders for the stream discontinuity they
                 * will encounter. */
                input_EscapeDiscontinuity( p_input );

448 449 450 451 452 453 454 455 456
                for( i = 0; i < p_input->stream.i_pgrm_number; i++ )
                {
                    pgrm_descriptor_t * p_pgrm
                                            = p_input->stream.pp_programs[i];

                    /* Reinitialize synchro. */
                    p_pgrm->i_synchro_state = SYNCHRO_REINIT;
                }
            }
457 458 459
            p_input->stream.p_new_area = NULL;
        }

460
        if( p_input->stream.p_selected_area->i_seek != NO_SEEK )
Sam Hocevar's avatar
 
Sam Hocevar committed
461
        {
462
            if( p_input->stream.p_selected_area->i_size > 0 )
463
            {
464
                unsigned int i;
465
                mtime_t      i_time;
466 467
                double f = (double)p_input->stream.p_selected_area->i_seek /
                           (double)p_input->stream.p_selected_area->i_size;
468

Christophe Massiot's avatar
Christophe Massiot committed
469
                vlc_mutex_unlock( &p_input->stream.stream_lock );
470
                demux_Control( p_input, DEMUX_SET_POSITION, f );
Christophe Massiot's avatar
Christophe Massiot committed
471
                vlc_mutex_lock( &p_input->stream.stream_lock );
472

473 474 475 476
                /* Escape all decoders for the stream discontinuity they
                 * will encounter. */
                input_EscapeDiscontinuity( p_input );

477 478
                for( i = 0; i < p_input->stream.i_pgrm_number; i++ )
                {
479
                    pgrm_descriptor_t * p_pgrm=p_input->stream.pp_programs[i];
480 481 482 483

                    /* Reinitialize synchro. */
                    p_pgrm->i_synchro_state = SYNCHRO_REINIT;
                }
484

Laurent Aimar's avatar
Laurent Aimar committed
485
                vlc_mutex_unlock( &p_input->stream.stream_lock );
486 487 488 489 490 491 492 493 494 495 496 497 498 499 500
                if( !demux_Control( p_input, DEMUX_GET_TIME, &i_time ) )
                {
                    int i;
                    vlc_value_t val;

                    /* Help in bar display */
                    val.i_time = i_time;
                    var_Change( p_input, "time", VLC_VAR_SETVALUE, &val, NULL );

                    /* Seek subs */
                    for( i = 0; i < p_input->p_sys->i_sub; i++ )
                    {
                        subtitle_Seek( p_input->p_sys->sub[i], i_time );
                    }
                }
501 502 503 504 505
                if( !demux_Control( p_input, DEMUX_GET_POSITION, &f ) )
                {
                    val.f_float = (float)f;
                    var_Change( p_input, "position", VLC_VAR_SETVALUE, &val, NULL );
                }
Laurent Aimar's avatar
Laurent Aimar committed
506
                vlc_mutex_lock( &p_input->stream.stream_lock );
507
            }
508
            p_input->stream.p_selected_area->i_seek = NO_SEEK;
Sam Hocevar's avatar
 
Sam Hocevar committed
509
        }
510

511 512 513 514 515 516 517 518 519 520 521 522
        if( p_input->stream.p_removed_es )
        {
            input_UnselectES( p_input, p_input->stream.p_removed_es );
            p_input->stream.p_removed_es = NULL;
        }

        if( p_input->stream.p_newly_selected_es )
        {
            input_SelectES( p_input, p_input->stream.p_newly_selected_es );
            p_input->stream.p_newly_selected_es = NULL;
        }

523 524 525 526 527 528 529 530 531 532 533 534 535 536
        if( p_input->stream.b_new_mute != MUTE_NO_CHANGE )
        {
            if( p_input->stream.b_new_mute )
            {
                input_EscapeAudioDiscontinuity( p_input );
            }

            vlc_mutex_lock( &p_input->stream.control.control_lock );
            p_input->stream.control.b_mute = p_input->stream.b_new_mute;
            vlc_mutex_unlock( &p_input->stream.control.control_lock );

            p_input->stream.b_new_mute = MUTE_NO_CHANGE;
        }

537
        vlc_mutex_unlock( &p_input->stream.stream_lock );
Sam Hocevar's avatar
 
Sam Hocevar committed
538

Christophe Massiot's avatar
Christophe Massiot committed
539 540
        /* Read and demultiplex some data. */
        i_count = p_input->pf_demux( p_input );
Sam Hocevar's avatar
 
Sam Hocevar committed
541

Gildas Bazin's avatar
 
Gildas Bazin committed
542
        if( i_count == 0 )
Sam Hocevar's avatar
 
Sam Hocevar committed
543
        {
544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565
            vlc_value_t repeat;

            var_Get( p_input, "input-repeat", &repeat );
            if( repeat.i_int == 0 || p_input->stream.i_area_nb <= 0 )
            {
                /* End of file - we do not set b_die because only the
                 * playlist is allowed to do so. */
                msg_Info( p_input, "EOF reached" );
                p_input->b_eof = 1;
            }
            else
            {
                msg_Dbg( p_input, "repeating the same input (%d)", repeat.i_int );
                if( repeat.i_int > 0 )
                {
                    repeat.i_int--;
                    var_Set( p_input, "input-repeat", repeat );
                }

                p_input->stream.p_new_area = p_input->stream.pp_areas[0];
                p_input->stream.p_new_area->i_seek = 0;
            }
566 567 568 569
        }
        else if( i_count < 0 )
        {
            p_input->b_error = 1;
570
        }
571 572 573

        if( !p_input->b_error && !p_input->b_eof && i_update_next < mdate() )
        {
574 575 576 577
            int i;
            mtime_t i_time;
            mtime_t i_length;
            double  d_pos;
578 579

            /* update input status variables */
580
            if( !demux_Control( p_input, DEMUX_GET_POSITION, &d_pos ) )
581
            {
582
                val.f_float = (float)d_pos;
583 584
                var_Change( p_input, "position", VLC_VAR_SETVALUE, &val, NULL );
            }
585
            if( !demux_Control( p_input, DEMUX_GET_TIME, &i_time ) )
586
            {
587
                val.i_time = i_time;
588 589
                var_Change( p_input, "time", VLC_VAR_SETVALUE, &val, NULL );
            }
590
            if( !demux_Control( p_input, DEMUX_GET_LENGTH, &i_length ) )
591
            {
592
                val.i_time = i_length;
593 594 595
                var_Change( p_input, "length", VLC_VAR_SETVALUE, &val, NULL );
            }

596 597 598 599 600 601 602
            /* Check stop-time */
            if( p_input->p_sys->i_stop_time > 0 && p_input->p_sys->i_stop_time < i_time )
            {
                msg_Warn( p_input, "EOF reached because of stop-time" );
                p_input->b_eof = 1;
            }

603 604 605 606 607 608
            /* update subs */
            for( i = 0; i < p_input->p_sys->i_sub; i++ )
            {
                subtitle_Demux( p_input->p_sys->sub[i], i_time );
            }

609
            i_update_next = mdate() + I64C(150000);
610
        }
611 612
    }

Sam Hocevar's avatar
 
Sam Hocevar committed
613
    if( p_input->b_error || p_input->b_eof )
614 615 616
    {
        ErrorThread( p_input );
    }
617

618
    EndThread( p_input );
Sam Hocevar's avatar
 
Sam Hocevar committed
619

Sam Hocevar's avatar
 
Sam Hocevar committed
620
    return 0;
621 622
}

623
/*****************************************************************************
Sam Hocevar's avatar
 
Sam Hocevar committed
624
 * InitThread: init the input Thread
625
 *****************************************************************************/
Sam Hocevar's avatar
 
Sam Hocevar committed
626
static int InitThread( input_thread_t * p_input )
Michel Kaempf's avatar
Michel Kaempf committed
627
{
628
    vlc_meta_t *p_meta = NULL, *p_meta_user = NULL;
629 630
//    float f_fps;
    double f_fps;
Sigmund Augdal Helberg's avatar
Sigmund Augdal Helberg committed
631
    mtime_t i_length;
632

Christophe Massiot's avatar
Christophe Massiot committed
633
    /* Parse source string. Syntax : [[<access>][/<demux>]:][<source>] */
634
    char * psz_parser = p_input->psz_dupsource = strdup(p_input->psz_source);
Gildas Bazin's avatar
 
Gildas Bazin committed
635
    vlc_value_t val;
636
    int64_t i_microsecondperframe;
Gildas Bazin's avatar
 
Gildas Bazin committed
637

638
    subtitle_demux_t *p_sub_toselect = NULL;
639
    char             *psz_sub_file = NULL;
640

Christophe Massiot's avatar
Christophe Massiot committed
641 642 643 644 645
    /* Skip the plug-in names */
    while( *psz_parser && *psz_parser != ':' )
    {
        psz_parser++;
    }
646
#if defined( WIN32 ) || defined( UNDER_CE )
Christophe Massiot's avatar
Christophe Massiot committed
647
    if( psz_parser - p_input->psz_dupsource == 1 )
Gildas Bazin's avatar
 
Gildas Bazin committed
648
    {
649
        msg_Warn( p_input, "drive letter %c: found in source string",
Christophe Massiot's avatar
Christophe Massiot committed
650
                           p_input->psz_dupsource[0] ) ;
Stéphane Borel's avatar
 
Stéphane Borel committed
651
        psz_parser = "";
Gildas Bazin's avatar
 
Gildas Bazin committed
652 653
    }
#endif
Sam Hocevar's avatar
 
Sam Hocevar committed
654

Christophe Massiot's avatar
Christophe Massiot committed
655
    if( !*psz_parser )
656
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
657
        p_input->psz_access = p_input->psz_demux = "";
Christophe Massiot's avatar
Christophe Massiot committed
658
        p_input->psz_name = p_input->psz_source;
Christophe Massiot's avatar
Christophe Massiot committed
659
        free( p_input->psz_dupsource );
660
        p_input->psz_dupsource = NULL;
Michel Kaempf's avatar
Michel Kaempf committed
661
    }
Christophe Massiot's avatar
Christophe Massiot committed
662 663 664
    else
    {
        *psz_parser++ = '\0';
665

Xavier Marchesini's avatar
 
Xavier Marchesini committed
666 667 668 669
        /* let's skip '//' */
        if( psz_parser[0] == '/' && psz_parser[1] == '/' )
        {
            psz_parser += 2 ;
670
        }
Xavier Marchesini's avatar
 
Xavier Marchesini committed
671 672

        p_input->psz_name = psz_parser ;
Sam Hocevar's avatar
 
Sam Hocevar committed
673

Christophe Massiot's avatar
Christophe Massiot committed
674
        /* Come back to parse the access and demux plug-ins */
Christophe Massiot's avatar
Christophe Massiot committed
675
        psz_parser = p_input->psz_dupsource;
Gildas Bazin's avatar
 
Gildas Bazin committed
676

Stéphane Borel's avatar
 
Stéphane Borel committed
677
        if( !*psz_parser )
Christophe Massiot's avatar
Christophe Massiot committed
678 679
        {
            /* No access */
Sam Hocevar's avatar
 
Sam Hocevar committed
680
            p_input->psz_access = "";
Christophe Massiot's avatar
Christophe Massiot committed
681 682 683 684
        }
        else if( *psz_parser == '/' )
        {
            /* No access */
Sam Hocevar's avatar
 
Sam Hocevar committed
685
            p_input->psz_access = "";
Christophe Massiot's avatar
Christophe Massiot committed
686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701
            psz_parser++;
        }
        else
        {
            p_input->psz_access = psz_parser;

            while( *psz_parser && *psz_parser != '/' )
            {
                psz_parser++;
            }

            if( *psz_parser == '/' )
            {
                *psz_parser++ = '\0';
            }
        }
Gildas Bazin's avatar
 
Gildas Bazin committed
702

Christophe Massiot's avatar
Christophe Massiot committed
703 704 705
        if( !*psz_parser )
        {
            /* No demux */
Sam Hocevar's avatar
 
Sam Hocevar committed
706
            p_input->psz_demux = "";
Christophe Massiot's avatar
Christophe Massiot committed
707 708 709 710 711
        }
        else
        {
            p_input->psz_demux = psz_parser;
        }
Sam Hocevar's avatar
 
Sam Hocevar committed
712
    }
Christophe Massiot's avatar
Christophe Massiot committed
713

714 715
    msg_Dbg( p_input, "access `%s', demux `%s', name `%s'",
             p_input->psz_access, p_input->psz_demux, p_input->psz_name );
Christophe Massiot's avatar
Christophe Massiot committed
716 717

    if( input_AccessInit( p_input ) == -1 )
718
    {
719 720 721 722 723 724
        free( p_input->psz_source );
        if( p_input->psz_dupsource != NULL )
        {
            free( p_input->psz_dupsource );
        }

725 726 727 728 729 730 731 732 733 734 735 736
        return VLC_EGENERIC;
    }

    /* Initialize optional stream output. (before demuxer)*/
    var_Get( p_input, "sout", &val );
    if( val.psz_string != NULL )
    {
        if ( *val.psz_string && (p_input->stream.p_sout =
             sout_NewInstance( p_input, val.psz_string )) == NULL )
        {
            msg_Err( p_input, "cannot start stream output instance, aborting" );
            free( val.psz_string );
737 738 739 740 741 742 743

            input_AccessEnd( p_input );
            free( p_input->psz_source );
            if( p_input->psz_dupsource != NULL )
            {
                free( p_input->psz_dupsource );
            }
744 745 746
            return VLC_EGENERIC;
        }
        free( val.psz_string );
747
    }
Christophe Massiot's avatar
Christophe Massiot committed
748

749
    p_input->p_es_out = input_EsOutNew( p_input );
750 751
    es_out_Control( p_input->p_es_out, ES_OUT_SET_ACTIVE, VLC_FALSE );
    es_out_Control( p_input->p_es_out, ES_OUT_SET_MODE, ES_OUT_MODE_NONE );
752

753
    /* Find and open appropriate access module */
754
    p_input->p_access = module_Need( p_input, "access",
Gildas Bazin's avatar
 
Gildas Bazin committed
755
                                     p_input->psz_access, VLC_TRUE );
Christophe Massiot's avatar
Christophe Massiot committed
756

757 758 759 760 761 762 763 764 765
    /* Maybe we had an encoded url */
    if( !p_input->p_access && strchr( p_input->psz_name, '%' ) )
    {
        DecodeUrl( p_input->psz_name );

        msg_Dbg( p_input, "retying with %s", p_input->psz_name );
        p_input->p_access = module_Need( p_input, "access",
                                         p_input->psz_access, VLC_TRUE );
    }
Gildas Bazin's avatar
 
Gildas Bazin committed
766 767 768 769
#ifndef WIN32      /* Remove this gross hack from the win32 build as colons
                    * are forbidden in filenames on Win32. */

    /* Maybe we got something like: /Volumes/toto:titi/gabu.mpg */
770 771 772 773 774 775 776 777 778
    if ( p_input->p_access == NULL
          && (*p_input->psz_demux || *p_input->psz_access) )
    {
        p_input->psz_access = p_input->psz_demux = "";
        p_input->psz_name = p_input->psz_source;
        free( p_input->psz_dupsource);
        p_input->psz_dupsource = NULL;

        p_input->p_access = module_Need( p_input, "access",
Gildas Bazin's avatar
 
Gildas Bazin committed
779
                                         p_input->psz_access, VLC_TRUE );
780
    }
Gildas Bazin's avatar
 
Gildas Bazin committed
781
#endif
782
    if( p_input->p_access == NULL )
783
    {
784
        msg_Err( p_input, "no suitable access module for `%s/%s://%s'",
785
                 p_input->psz_access, p_input->psz_demux, p_input->psz_name );
786 787 788 789
        if ( p_input->stream.p_sout != NULL )
        {
            sout_DeleteInstance( p_input->stream.p_sout );
        }
790 791 792 793 794 795 796

        input_AccessEnd( p_input );
        free( p_input->psz_source );
        if( p_input->psz_dupsource != NULL )
        {
            free( p_input->psz_dupsource );
        }
Gildas Bazin's avatar
 
Gildas Bazin committed
797
        input_EsOutDelete( p_input->p_es_out );
798
        return VLC_EGENERIC;
799
    }
Christophe Massiot's avatar
Christophe Massiot committed
800 801 802

    /* Waiting for stream. */
    if( p_input->i_mtu )
Christophe Massiot's avatar
Christophe Massiot committed
803
    {
Christophe Massiot's avatar
Christophe Massiot committed
804
        p_input->i_bufsize = p_input->i_mtu;
Christophe Massiot's avatar
Christophe Massiot committed
805
    }
806 807
    else
    {
Christophe Massiot's avatar
Christophe Massiot committed
808
        p_input->i_bufsize = INPUT_DEFAULT_BUFSIZE;
809
    }
810

Gildas Bazin's avatar
 
Gildas Bazin committed
811 812
    /* If the desynchronisation requested by the user is < 0, we need to
     * cache more data. */
Gildas Bazin's avatar
 
Gildas Bazin committed
813 814 815 816
    var_Create( p_input, "audio-desync", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
    var_Get( p_input, "audio-desync", &val );
    if( val.i_int < 0 )
        p_input->i_pts_delay -= (val.i_int * 1000);
Gildas Bazin's avatar
 
Gildas Bazin committed
817

Sam Hocevar's avatar
 
Sam Hocevar committed
818
    if( p_input->p_current_data == NULL && p_input->pf_read != NULL )
819
    {
Christophe Massiot's avatar
Christophe Massiot committed
820 821
        while( !input_FillBuffer( p_input ) )
        {
822
            if( p_input->b_die || p_input->b_error || p_input->b_eof )
Christophe Massiot's avatar
Christophe Massiot committed
823
            {
824
                module_Unneed( p_input, p_input->p_access );
825 826 827 828
                if ( p_input->stream.p_sout != NULL )
                {
                    sout_DeleteInstance( p_input->stream.p_sout );
                }
829 830 831 832 833 834
                input_AccessEnd( p_input );
                free( p_input->psz_source );
                if( p_input->psz_dupsource != NULL )
                {
                    free( p_input->psz_dupsource );
                }
Gildas Bazin's avatar
 
Gildas Bazin committed
835
                input_EsOutDelete( p_input->p_es_out );
836
                return VLC_EGENERIC;
Christophe Massiot's avatar
Christophe Massiot committed
837 838
            }
        }
839
    }
Sam Hocevar's avatar
 
Sam Hocevar committed
840

841
    /* Create the stream_t facilities */
842
    p_input->s = input_StreamNew( p_input );
843 844
    if( p_input->s == NULL )
    {
Clément Stenac's avatar
Clément Stenac committed
845
        /* should never occur yet */
846

Clément Stenac's avatar
Clément Stenac committed
847
        msg_Err( p_input, "cannot create stream_t" );
848

849 850 851 852 853
        module_Unneed( p_input, p_input->p_access );
        if ( p_input->stream.p_sout != NULL )
        {
            sout_DeleteInstance( p_input->stream.p_sout );
        }
854 855 856 857 858 859
        input_AccessEnd( p_input );
        free( p_input->psz_source );
        if( p_input->psz_dupsource != NULL )
        {
            free( p_input->psz_dupsource );
        }
Gildas Bazin's avatar
 
Gildas Bazin committed
860
        input_EsOutDelete( p_input->p_es_out );
861 862 863
        return VLC_EGENERIC;
    }

864
    /* Find and open appropriate demux module */
Gildas Bazin's avatar
 
Gildas Bazin committed
865 866 867
    p_input->p_demux =
        module_Need( p_input, "demux",
                     (p_input->psz_demux && *p_input->psz_demux) ?
Gildas Bazin's avatar
 
Gildas Bazin committed
868 869 870
                     p_input->psz_demux : "$demux",
                     (p_input->psz_demux && *p_input->psz_demux) ?
                     VLC_TRUE : VLC_FALSE );
Sam Hocevar's avatar
 
Sam Hocevar committed
871

872
    if( p_input->p_demux == NULL )
873
    {
874
        msg_Err( p_input, "no suitable demux module for `%s/%s://%s'",
875
                 p_input->psz_access, p_input->psz_demux, p_input->psz_name );
876

877
        input_StreamDelete( p_input->s );
878
        module_Unneed( p_input, p_input->p_access );
879
        if ( p_input->stream.p_sout != NULL )
880
        {
881
            sout_DeleteInstance( p_input->stream.p_sout );
882
        }
883 884 885 886 887 888
        input_AccessEnd( p_input );
        free( p_input->psz_source );
        if( p_input->psz_dupsource != NULL )
        {
            free( p_input->psz_dupsource );
        }
Gildas Bazin's avatar
 
Gildas Bazin committed
889
        input_EsOutDelete( p_input->p_es_out );
890
        return VLC_EGENERIC;
891 892
    }

893 894 895 896 897
    /* Init input_thread_sys_t */
    p_input->p_sys = malloc( sizeof( input_thread_sys_t ) );
    p_input->p_sys->i_sub = 0;
    p_input->p_sys->sub   = NULL;

898 899
    p_input->p_sys->i_stop_time = 0;

900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949
    /* Get meta information from user */
    var_Create( p_input, "meta-title", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
    var_Create( p_input, "meta-author", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
    var_Create( p_input, "meta-artist", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
    var_Create( p_input, "meta-genre", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
    var_Create( p_input, "meta-copyright", VLC_VAR_STRING | VLC_VAR_DOINHERIT);
    var_Create( p_input, "meta-description", VLC_VAR_STRING|VLC_VAR_DOINHERIT);
    var_Create( p_input, "meta-date", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
    var_Create( p_input, "meta-url", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
    if( (p_meta_user = vlc_meta_New()) )
    {
        vlc_value_t val;

        var_Get( p_input, "meta-title", &val );
        if( val.psz_string && *val.psz_string )
            vlc_meta_Add( p_meta_user, VLC_META_TITLE, val.psz_string );
        if( val.psz_string ) free( val.psz_string );
        var_Get( p_input, "meta-author", &val );
        if( val.psz_string && *val.psz_string )
            vlc_meta_Add( p_meta_user, VLC_META_AUTHOR, val.psz_string );
        if( val.psz_string ) free( val.psz_string );
        var_Get( p_input, "meta-artist", &val );
        if( val.psz_string && *val.psz_string )
            vlc_meta_Add( p_meta_user, VLC_META_ARTIST, val.psz_string );
        if( val.psz_string ) free( val.psz_string );
        var_Get( p_input, "meta-genre", &val );
        if( val.psz_string && *val.psz_string )
            vlc_meta_Add( p_meta_user, VLC_META_GENRE, val.psz_string );
        if( val.psz_string ) free( val.psz_string );
        var_Get( p_input, "meta-copyright", &val );
        if( val.psz_string && *val.psz_string )
            vlc_meta_Add( p_meta_user, VLC_META_COPYRIGHT, val.psz_string );
        if( val.psz_string ) free( val.psz_string );
        var_Get( p_input, "meta-description", &val );
        if( val.psz_string && *val.psz_string )
            vlc_meta_Add( p_meta_user, VLC_META_DESCRIPTION, val.psz_string );
        if( val.psz_string ) free( val.psz_string );
        var_Get( p_input, "meta-date", &val );
        if( val.psz_string && *val.psz_string )
            vlc_meta_Add( p_meta_user, VLC_META_DATE, val.psz_string );
        if( val.psz_string ) free( val.psz_string );
        var_Get( p_input, "meta-url", &val );
        if( val.psz_string && *val.psz_string )
            vlc_meta_Add( p_meta_user, VLC_META_URL, val.psz_string );
        if( val.psz_string ) free( val.psz_string );
    }

    /* Get meta informations from demuxer */
    if( !demux_Control( p_input, DEMUX_GET_META, &p_meta ) ||
        ( p_meta_user && p_meta_user->i_meta ) )
950 951 952
    {
        int i;

953 954 955 956
        /* Merge demux and user metadata */
        if( !p_meta ){ p_meta = p_meta_user; p_meta_user = NULL; }
        else if( p_meta && p_meta_user ) vlc_meta_Merge( p_meta, p_meta_user );

957
        msg_Dbg( p_input, "meta informations:" );
958
        if( p_meta->i_meta > 0 )
959
        {
960
            for( i = 0; i < p_meta->i_meta; i++ )
961
            {
962 963
                msg_Dbg( p_input, "  - '%s' = '%s'", _(p_meta->name[i]),
                         p_meta->value[i] );
964 965 966 967
                if( !strcmp( p_meta->name[i], VLC_META_TITLE ) &&
                    p_meta->value[i] )
                    input_Control( p_input, INPUT_SET_NAME, p_meta->value[i] );

968
                if( !strcmp( p_meta->name[i], VLC_META_AUTHOR ) )
969 970 971 972 973
                    input_Control( p_input, INPUT_ADD_INFO, _("General"),
                                   _("Author"), p_meta->value[i] );

                input_Control( p_input, INPUT_ADD_INFO, _("File"),
                              _(p_meta->name[i]), "%s", p_meta->value[i] );
974 975
            }
        }
976
        for( i = 0; i < p_meta->i_track; i++ )
977
        {
978
            vlc_meta_t *tk = p_meta->track[i];
979 980 981 982 983 984 985 986 987 988
            int j;

            msg_Dbg( p_input, "  - track[%d]:", i );
            if( tk->i_meta > 0 )
            {
                char *psz_cat = malloc( strlen(_("Stream")) + 10 );
                sprintf( psz_cat, "%s %d", _("Stream"), i );

                for( j = 0; j < tk->i_meta; j++ )
                {
989 990
                    msg_Dbg( p_input, "     - '%s' = '%s'", _(tk->name[j]),
                             tk->value[j] );
991 992 993

                    input_Control( p_input, INPUT_ADD_INFO, psz_cat,
                                   _(tk->name[j]), "%s", tk->value[j] );
994 995 996 997
                }
            }
        }

998 999
        if( p_input->stream.p_sout && p_input->stream.p_sout->p_meta == NULL )
        {
1000
            p_input->stream.p_sout->p_meta = p_meta;
1001 1002 1003
        }
        else
        {
1004
            vlc_meta_Delete( p_meta );
1005
        }
1006
    }
1007
    if( p_meta_user ) vlc_meta_Delete( p_meta_user );
1008

1009 1010 1011
    /* Get length */
    if( !demux_Control( p_input, DEMUX_GET_LENGTH, &i_length ) &&
        i_length > 0 )
Sigmund Augdal Helberg's avatar
Sigmund Augdal Helberg committed
1012
    {
1013 1014 1015 1016 1017 1018 1019 1020
        char psz_buffer[MSTRTIME_MAX_SIZE];

        vlc_mutex_lock( &p_input->p_item->lock );
        p_input->p_item->i_duration = i_length;
        vlc_mutex_unlock( &p_input->p_item->lock );

        input_Control( p_input, INPUT_ADD_INFO, _("General"), _("Duration"),
                       msecstotimestr( psz_buffer, i_length / 1000 ) );
1021 1022 1023 1024 1025

        /* Set start time */
        var_Get( p_input, "start-time", &val );
        if(  val.i_int > 0 )
        {
1026
            double f_pos = val.i_int * I64C(1000000) / (double)i_length;
1027 1028 1029

            if( f_pos >= 1.0 )
            {
1030 1031
                msg_Warn( p_input, "invalid start-time, ignored (start-time "
                          ">= media length)" );
1032 1033 1034 1035 1036 1037 1038 1039 1040
            }
            else
            {
                p_input->stream.p_selected_area->i_seek =
                    (int64_t)( f_pos * (double)p_input->stream.p_selected_area->i_size );

                msg_Dbg( p_input, "start-time %ds (%2.2f)", val.i_int, f_pos );
            }
        }
1041
    }