input.c 48 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
};

Sam Hocevar's avatar
 
Sam Hocevar committed
59
static  int RunThread       ( input_thread_t *p_input );
Sam Hocevar's avatar
 
Sam Hocevar committed
60 61 62
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

Gildas Bazin's avatar
 
Gildas Bazin committed
64 65
static void ParseOption     ( input_thread_t *p_input,
                              const char *psz_option );
66

67 68 69 70 71 72 73 74 75 76 77
/*****************************************************************************
 * 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
78 79
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
80

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

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

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

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

Gildas Bazin's avatar
 
Gildas Bazin committed
106
    /* Parse input options */
107 108
    vlc_mutex_lock( &p_item->lock );
    for( i = 0; i < p_item->i_options; i++ )
Gildas Bazin's avatar
 
Gildas Bazin committed
109
    {
110 111
        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
112
    }
113
    vlc_mutex_unlock( &p_item->lock );
Gildas Bazin's avatar
 
Gildas Bazin committed
114

Gildas Bazin's avatar
 
Gildas Bazin committed
115 116 117 118 119
    /* 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 );
120
    var_Create( p_input, "sub-file", VLC_VAR_FILE | VLC_VAR_DOINHERIT );
121 122 123 124
    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
125 126

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

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

135 136 137 138
    /* 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 );

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

142 143 144
    /* play status */

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

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

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

181 182 183 184
    /* 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
185

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

    /* Set target */
192 193 194
    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
195

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

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

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

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

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

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

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

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

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

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

Sam Hocevar's avatar
 
Sam Hocevar committed
245 246 247 248
    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
249
    /* By default there is one area in a stream */
Gildas Bazin's avatar
 
Gildas Bazin committed
250
    input_AddArea( p_input, 0, 1 );
251
    p_input->stream.p_selected_area = p_input->stream.pp_areas[0];
Stéphane Borel's avatar
 
Stéphane Borel committed
252

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

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

Gildas Bazin's avatar
Gildas Bazin committed
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 300 301
    /* 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 ) )
                {
302
                    seekpoint.i_byte_offset = atoll(psz_start + 6);
Gildas Bazin's avatar
Gildas Bazin committed
303 304 305
                }
                else if( !strncmp( psz_start, "time=", 5 ) )
                {
306
                    seekpoint.i_time_offset = atoll(psz_start + 5) * 1000000;
Gildas Bazin's avatar
Gildas Bazin committed
307 308 309 310 311 312 313 314 315 316 317 318
                }
                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 );
    }

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

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

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

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

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

/*****************************************************************************
 * 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 */
357
    vlc_thread_join( p_input );
Sam Hocevar's avatar
 
Sam Hocevar committed
358 359 360

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

423 424 425 426 427 428 429 430 431 432 433
                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;
        }
434

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

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

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

447 448 449 450 451 452 453 454 455
                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;
                }
            }
456 457 458
            p_input->stream.p_new_area = NULL;
        }

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

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

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

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

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

Laurent Aimar's avatar
Laurent Aimar committed
484
                vlc_mutex_unlock( &p_input->stream.stream_lock );
485 486 487 488 489 490 491 492 493 494 495 496 497 498 499
                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 );
                    }
                }
Laurent Aimar's avatar
Laurent Aimar committed
500
                vlc_mutex_lock( &p_input->stream.stream_lock );
501
            }
502
            p_input->stream.p_selected_area->i_seek = NO_SEEK;
Sam Hocevar's avatar
 
Sam Hocevar committed
503
        }
504

505 506 507 508 509 510 511 512 513 514 515 516
        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;
        }

517 518 519 520 521 522 523 524 525 526 527 528 529 530
        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;
        }

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

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

Gildas Bazin's avatar
 
Gildas Bazin committed
536
        if( i_count == 0 )
Sam Hocevar's avatar
 
Sam Hocevar committed
537
        {
538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559
            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;
            }
560 561 562 563
        }
        else if( i_count < 0 )
        {
            p_input->b_error = 1;
564
        }
565 566 567

        if( !p_input->b_error && !p_input->b_eof && i_update_next < mdate() )
        {
568 569 570 571
            int i;
            mtime_t i_time;
            mtime_t i_length;
            double  d_pos;
572 573

            /* update input status variables */
574
            if( !demux_Control( p_input, DEMUX_GET_POSITION, &d_pos ) )
575
            {
576
                val.f_float = (float)d_pos;
577 578
                var_Change( p_input, "position", VLC_VAR_SETVALUE, &val, NULL );
            }
579
            if( !demux_Control( p_input, DEMUX_GET_TIME, &i_time ) )
580
            {
581
                val.i_time = i_time;
582 583
                var_Change( p_input, "time", VLC_VAR_SETVALUE, &val, NULL );
            }
584
            if( !demux_Control( p_input, DEMUX_GET_LENGTH, &i_length ) )
585
            {
586
                val.i_time = i_length;
587 588 589
                var_Change( p_input, "length", VLC_VAR_SETVALUE, &val, NULL );
            }

590 591 592 593 594 595 596
            /* 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;
            }

597 598 599 600 601 602
            /* update subs */
            for( i = 0; i < p_input->p_sys->i_sub; i++ )
            {
                subtitle_Demux( p_input->p_sys->sub[i], i_time );
            }

603
            i_update_next = mdate() + I64C(150000);
604
        }
605 606
    }

Sam Hocevar's avatar
 
Sam Hocevar committed
607
    if( p_input->b_error || p_input->b_eof )
608 609 610
    {
        ErrorThread( p_input );
    }
611

612
    EndThread( p_input );
Sam Hocevar's avatar
 
Sam Hocevar committed
613

Sam Hocevar's avatar
 
Sam Hocevar committed
614
    return 0;
615 616
}

617
/*****************************************************************************
Sam Hocevar's avatar
 
Sam Hocevar committed
618
 * InitThread: init the input Thread
619
 *****************************************************************************/
Sam Hocevar's avatar
 
Sam Hocevar committed
620
static int InitThread( input_thread_t * p_input )
Michel Kaempf's avatar
Michel Kaempf committed
621
{
622
    vlc_meta_t *p_meta = NULL, *p_meta_user = NULL;
623 624
//    float f_fps;
    double f_fps;
Sigmund Augdal Helberg's avatar
Sigmund Augdal Helberg committed
625
    mtime_t i_length;
626

Christophe Massiot's avatar
Christophe Massiot committed
627
    /* Parse source string. Syntax : [[<access>][/<demux>]:][<source>] */
628
    char * psz_parser = p_input->psz_dupsource = strdup(p_input->psz_source);
Gildas Bazin's avatar
 
Gildas Bazin committed
629
    vlc_value_t val;
630
    int64_t i_microsecondperframe;
Gildas Bazin's avatar
 
Gildas Bazin committed
631

632
    subtitle_demux_t *p_sub_toselect = NULL;
633
    char             *psz_sub_file = NULL;
634

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

Christophe Massiot's avatar
Christophe Massiot committed
649
    if( !*psz_parser )
650
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
651
        p_input->psz_access = p_input->psz_demux = "";
Christophe Massiot's avatar
Christophe Massiot committed
652
        p_input->psz_name = p_input->psz_source;
Christophe Massiot's avatar
Christophe Massiot committed
653
        free( p_input->psz_dupsource );
654
        p_input->psz_dupsource = NULL;
Michel Kaempf's avatar
Michel Kaempf committed
655
    }
Christophe Massiot's avatar
Christophe Massiot committed
656 657 658
    else
    {
        *psz_parser++ = '\0';
659

Xavier Marchesini's avatar
 
Xavier Marchesini committed
660 661 662 663
        /* let's skip '//' */
        if( psz_parser[0] == '/' && psz_parser[1] == '/' )
        {
            psz_parser += 2 ;
664
        }
Xavier Marchesini's avatar
 
Xavier Marchesini committed
665 666

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

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

Stéphane Borel's avatar
 
Stéphane Borel committed
671
        if( !*psz_parser )
Christophe Massiot's avatar
Christophe Massiot committed
672 673
        {
            /* No access */
Sam Hocevar's avatar
 
Sam Hocevar committed
674
            p_input->psz_access = "";
Christophe Massiot's avatar
Christophe Massiot committed
675 676 677 678
        }
        else if( *psz_parser == '/' )
        {
            /* No access */
Sam Hocevar's avatar
 
Sam Hocevar committed
679
            p_input->psz_access = "";
Christophe Massiot's avatar
Christophe Massiot committed
680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695
            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
696

Christophe Massiot's avatar
Christophe Massiot committed
697 698 699
        if( !*psz_parser )
        {
            /* No demux */
Sam Hocevar's avatar
 
Sam Hocevar committed
700
            p_input->psz_demux = "";
Christophe Massiot's avatar
Christophe Massiot committed
701 702 703 704 705
        }
        else
        {
            p_input->psz_demux = psz_parser;
        }
Sam Hocevar's avatar
 
Sam Hocevar committed
706
    }
Christophe Massiot's avatar
Christophe Massiot committed
707

708 709
    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
710 711

    if( input_AccessInit( p_input ) == -1 )
712
    {
713 714 715 716 717 718
        free( p_input->psz_source );
        if( p_input->psz_dupsource != NULL )
        {
            free( p_input->psz_dupsource );
        }

719 720 721 722 723 724 725 726 727 728 729 730
        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 );
731 732 733 734 735 736 737

            input_AccessEnd( p_input );
            free( p_input->psz_source );
            if( p_input->psz_dupsource != NULL )
            {
                free( p_input->psz_dupsource );
            }
738 739 740
            return VLC_EGENERIC;
        }
        free( val.psz_string );
741
    }
Christophe Massiot's avatar
Christophe Massiot committed
742

743
    p_input->p_es_out = input_EsOutNew( p_input );
744 745
    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 );
746

747
    /* Find and open appropriate access module */
748
    p_input->p_access = module_Need( p_input, "access",
Gildas Bazin's avatar
 
Gildas Bazin committed
749
                                     p_input->psz_access, VLC_TRUE );
Christophe Massiot's avatar
Christophe Massiot committed
750

Gildas Bazin's avatar
 
Gildas Bazin committed
751 752 753 754
#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 */
755 756 757 758 759 760 761 762 763
    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
764
                                         p_input->psz_access, VLC_TRUE );
765
    }
Gildas Bazin's avatar
 
Gildas Bazin committed
766
#endif
767

768
    if( p_input->p_access == NULL )
769
    {
770
        msg_Err( p_input, "no suitable access module for `%s/%s://%s'",
771
                 p_input->psz_access, p_input->psz_demux, p_input->psz_name );
772 773 774 775
        if ( p_input->stream.p_sout != NULL )
        {
            sout_DeleteInstance( p_input->stream.p_sout );
        }
776 777 778 779 780 781 782

        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
783
        input_EsOutDelete( p_input->p_es_out );
784
        return VLC_EGENERIC;
785
    }
Christophe Massiot's avatar
Christophe Massiot committed
786 787 788

    /* Waiting for stream. */
    if( p_input->i_mtu )
Christophe Massiot's avatar
Christophe Massiot committed
789
    {
Christophe Massiot's avatar
Christophe Massiot committed
790
        p_input->i_bufsize = p_input->i_mtu;
Christophe Massiot's avatar
Christophe Massiot committed
791
    }
792 793
    else
    {
Christophe Massiot's avatar
Christophe Massiot committed
794
        p_input->i_bufsize = INPUT_DEFAULT_BUFSIZE;
795
    }
796

Gildas Bazin's avatar
 
Gildas Bazin committed
797 798
    /* If the desynchronisation requested by the user is < 0, we need to
     * cache more data. */
Gildas Bazin's avatar
 
Gildas Bazin committed
799 800 801 802
    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
803

Sam Hocevar's avatar
 
Sam Hocevar committed
804
    if( p_input->p_current_data == NULL && p_input->pf_read != NULL )
805
    {
Christophe Massiot's avatar
Christophe Massiot committed
806 807
        while( !input_FillBuffer( p_input ) )
        {
808
            if( p_input->b_die || p_input->b_error || p_input->b_eof )
Christophe Massiot's avatar
Christophe Massiot committed
809
            {
810
                module_Unneed( p_input, p_input->p_access );
811 812 813 814
                if ( p_input->stream.p_sout != NULL )
                {
                    sout_DeleteInstance( p_input->stream.p_sout );
                }
815 816 817 818 819 820
                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
821
                input_EsOutDelete( p_input->p_es_out );
822
                return VLC_EGENERIC;
Christophe Massiot's avatar
Christophe Massiot committed
823 824
            }
        }
825
    }
Sam Hocevar's avatar
 
Sam Hocevar committed
826

827
    /* Create the stream_t facilities */
828
    p_input->s = input_StreamNew( p_input );
829 830
    if( p_input->s == NULL )
    {
Clément Stenac's avatar
Clément Stenac committed
831
        /* should never occur yet */
832

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

835 836 837 838 839
        module_Unneed( p_input, p_input->p_access );
        if ( p_input->stream.p_sout != NULL )
        {
            sout_DeleteInstance( p_input->stream.p_sout );
        }
840 841 842 843 844 845
        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
846
        input_EsOutDelete( p_input->p_es_out );
847 848 849
        return VLC_EGENERIC;
    }

850
    /* Find and open appropriate demux module */
Gildas Bazin's avatar
 
Gildas Bazin committed
851 852 853
    p_input->p_demux =
        module_Need( p_input, "demux",
                     (p_input->psz_demux && *p_input->psz_demux) ?
Gildas Bazin's avatar
 
Gildas Bazin committed
854 855 856
                     p_input->psz_demux : "$demux",
                     (p_input->psz_demux && *p_input->psz_demux) ?
                     VLC_TRUE : VLC_FALSE );
Sam Hocevar's avatar
 
Sam Hocevar committed
857

858
    if( p_input->p_demux == NULL )
859
    {
860
        msg_Err( p_input, "no suitable demux module for `%s/%s://%s'",
861
                 p_input->psz_access, p_input->psz_demux, p_input->psz_name );
862

863
        input_StreamDelete( p_input->s );
864
        module_Unneed( p_input, p_input->p_access );
865
        if ( p_input->stream.p_sout != NULL )
866
        {
867
            sout_DeleteInstance( p_input->stream.p_sout );
868
        }
869 870 871 872 873 874
        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
875
        input_EsOutDelete( p_input->p_es_out );
876
        return VLC_EGENERIC;
877 878
    }

879 880 881 882 883
    /* 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;

884 885
    p_input->p_sys->i_stop_time = 0;

886 887 888 889 890 891 892 893 894 895 896 897 898 899 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
    /* 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 ) )
936 937 938
    {
        int i;

939 940 941 942
        /* 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 );

943
        msg_Dbg( p_input, "meta informations:" );
944
        if( p_meta->i_meta > 0 )
945
        {
946
            for( i = 0; i < p_meta->i_meta; i++ )
947
            {
948 949
                msg_Dbg( p_input, "  - '%s' = '%s'", _(p_meta->name[i]),
                         p_meta->value[i] );
950 951 952 953
                if( !strcmp( p_meta->name[i], VLC_META_TITLE ) &&
                    p_meta->value[i] )
                    input_Control( p_input, INPUT_SET_NAME, p_meta->value[i] );

954
                if( !strcmp( p_meta->name[i], VLC_META_AUTHOR ) )
955 956 957 958 959
                    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] );
960 961
            }
        }
962
        for( i = 0; i < p_meta->i_track; i++ )
963
        {
964
            vlc_meta_t *tk = p_meta->track[i];
965 966 967 968 969 970 971 972 973 974
            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++ )
                {
975 976
                    msg_Dbg( p_input, "     - '%s' = '%s'", _(tk->name[j]),
                             tk->value[j] );
977 978 979

                    input_Control( p_input, INPUT_ADD_INFO, psz_cat,
                                   _(tk->name[j]), "%s", tk->value[j] );
980 981 982 983
                }
            }
        }

984 985
        if( p_input->stream.p_sout && p_input->stream.p_sout->p_meta == NULL )
        {
986
            p_input->stream.p_sout->p_meta = p_meta;
987 988 989
        }
        else
        {
990
            vlc_meta_Delete( p_meta );
991
        }
992
    }
993
    if( p_meta_user ) vlc_meta_Delete( p_meta_user );
994

995 996 997
    /* Get length */
    if( !demux_Control( p_input, DEMUX_GET_LENGTH, &i_length ) &&
        i_length > 0 )
Sigmund Augdal Helberg's avatar
Sigmund Augdal Helberg committed
998
    {
999 1000 1001 1002 1003 1004 1005 1006
        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 ) );
1007 1008 1009 1010 1011

        /* Set start time */
        var_Get( p_input, "start-time", &val );
        if(  val.i_int > 0 )
        {
1012
            double f_pos = val.i_int * I64C(1000000) / (double)i_length;
1013 1014 1015

            if( f_pos >= 1.0 )
            {
1016 1017
                msg_Warn( p_input, "invalid start-time, ignored (start-time "
                          ">= media length)" );
1018 1019 1020 1021 1022 1023 1024 1025 1026
            }
            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 );
            }
        }
1027
    }
1028

1029 1030 1031 1032 1033
    /* Set stop-time and check validity */
    var_Get( p_input, "stop-time", &val );
    if( val.i_int > 0 )
    {
        vlc_value_t start;
1034

Laurent Aimar's avatar