input.c 61.3 KB
Newer Older
1 2
/*****************************************************************************
 * input.c: input thread
3
 *****************************************************************************
Clément Stenac's avatar
Clément Stenac committed
4
 * Copyright (C) 1998-2004 VideoLAN
5
 * $Id$
6
 *
7
 * Authors: Christophe Massiot <massiot@via.ecp.fr>
Laurent Aimar's avatar
Laurent Aimar committed
8
 *          Laurent Aimar <fenrir@via.ecp.fr>
9 10 11 12 13
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
14
 *
15 16
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 18
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
19
 *
20 21 22
 * 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.
23
 *****************************************************************************/
Michel Kaempf's avatar
Michel Kaempf committed
24

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

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

Laurent Aimar's avatar
Laurent Aimar committed
35
#include "input_internal.h"
36

37 38
#include "stream_output.h"

39
#include "vlc_interface.h"
40
#include "vlc_meta.h"
Sam Hocevar's avatar
 
Sam Hocevar committed
41

42
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
43
 * Local prototypes
44
 *****************************************************************************/
Laurent Aimar's avatar
Laurent Aimar committed
45 46 47 48 49 50 51 52 53
static  int Run  ( input_thread_t *p_input );

static  int Init ( input_thread_t *p_input );
static void Error( input_thread_t *p_input );
static void End  ( input_thread_t *p_input );

static inline int ControlPopNoLock( input_thread_t *, int *, vlc_value_t * );
static void       ControlReduce( input_thread_t * );
static vlc_bool_t Control( input_thread_t *, int, vlc_value_t );
54

55

Laurent Aimar's avatar
Laurent Aimar committed
56 57
static void UpdateFromAccess( input_thread_t * );
static void UpdateFromDemux( input_thread_t * );
Michel Kaempf's avatar
Michel Kaempf committed
58

59 60 61
static void ParseOption( input_thread_t *p_input, const char *psz_option );

static void DecodeUrl  ( char * );
62

63
/*****************************************************************************
64
 * input_CreateThread: creates a new input thread
65
 *****************************************************************************
66 67
 * This function creates a new input, and returns a pointer
 * to its description. On error, it returns NULL.
Laurent Aimar's avatar
Laurent Aimar committed
68 69 70 71 72 73 74 75 76 77
 *
 * Variables for _public_ use:
 * * Get and Set:
 *  - state
 *  - rate,rate-slower, rate-faster
 *  - position, position-offset
 *  - time, time-offset
 *  - title,title-next,title-prev
 *  - chapter,chapter-next, chapter-prev
 *  - program, audio-es, video-es, spu-es
78
 *  - audio-delay, spu-delay
Laurent Aimar's avatar
Laurent Aimar committed
79 80 81 82
 *  - bookmark
 * * Get only:
 *  - length
 *  - bookmarks
83
 *  - seekable (if you can seek, it doesn't say if 'bar display' has be shown or not, for that check position != 0.0)
Laurent Aimar's avatar
Laurent Aimar committed
84 85 86 87
 * * For intf callback upon changes
 *  - intf-change
 * TODO explain when Callback is called
 * TODO complete this list (?)
88
 *****************************************************************************/
89 90
input_thread_t *__input_CreateThread( vlc_object_t *p_parent,
                                      input_item_t *p_item )
91

Michel Kaempf's avatar
Michel Kaempf committed
92
{
93 94
    input_thread_t *p_input;                        /* thread descriptor */
    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

Laurent Aimar's avatar
Laurent Aimar committed
104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137
    /* Init Common fields */
    p_input->b_eof = VLC_FALSE;
    p_input->b_can_pace_control = VLC_TRUE;
    p_input->i_start = 0;
    p_input->i_time  = 0;
    p_input->i_stop  = 0;
    p_input->i_title = 0;
    p_input->title   = NULL;
    p_input->i_state = INIT_S;
    p_input->i_rate  = INPUT_RATE_DEFAULT;
    p_input->i_bookmark = 0;
    p_input->bookmark = NULL;
    p_input->p_es_out = NULL;
    p_input->p_sout  = NULL;
    p_input->b_out_pace_control = VLC_FALSE;
    p_input->i_pts_delay = 0;


    /* Init Input fields */
    p_input->input.p_item = p_item;
    p_input->input.p_access = NULL;
    p_input->input.p_stream = NULL;
    p_input->input.p_demux  = NULL;
    p_input->input.b_title_demux = VLC_FALSE;
    p_input->input.i_title  = 0;
    p_input->input.title    = NULL;
    p_input->input.b_can_pace_control = VLC_TRUE;
    p_input->input.b_eof = VLC_FALSE;
    p_input->input.i_cr_average = 0;

    /* Init control buffer */
    vlc_mutex_init( p_input, &p_input->lock_control );
    p_input->i_control = 0;
    p_input->p_sys = NULL;
138

Gildas Bazin's avatar
 
Gildas Bazin committed
139
    /* Parse input options */
140 141
    vlc_mutex_lock( &p_item->lock );
    for( i = 0; i < p_item->i_options; i++ )
Gildas Bazin's avatar
 
Gildas Bazin committed
142
    {
143 144
        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
145
    }
146
    vlc_mutex_unlock( &p_item->lock );
Gildas Bazin's avatar
 
Gildas Bazin committed
147

Laurent Aimar's avatar
Laurent Aimar committed
148 149
    /* Create Object Variables for private use only */
    input_ConfigVarInit( p_input );
Michel Kaempf's avatar
Michel Kaempf committed
150

Laurent Aimar's avatar
Laurent Aimar committed
151 152 153
    /* Create Objects variables for public Get and Set */
    input_ControlVarInit( p_input );
    p_input->input.i_cr_average = var_GetInteger( p_input, "cr-average" );
Gildas Bazin's avatar
Gildas Bazin committed
154

Laurent Aimar's avatar
Laurent Aimar committed
155 156
#if 0
    /* TODO */
Gildas Bazin's avatar
Gildas Bazin committed
157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186
    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 ) )
                {
187
                    seekpoint.i_byte_offset = atoll(psz_start + 6);
Gildas Bazin's avatar
Gildas Bazin committed
188 189 190
                }
                else if( !strncmp( psz_start, "time=", 5 ) )
                {
191
                    seekpoint.i_time_offset = atoll(psz_start + 5) * 1000000;
Gildas Bazin's avatar
Gildas Bazin committed
192 193 194 195 196 197 198 199 200 201 202
                }
                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 );
    }
Laurent Aimar's avatar
Laurent Aimar committed
203
#endif
Gildas Bazin's avatar
Gildas Bazin committed
204

Laurent Aimar's avatar
Laurent Aimar committed
205
    /* Now we can attach our new input */
206
    vlc_object_attach( p_input, p_parent );
Sam Hocevar's avatar
 
Sam Hocevar committed
207

Sam Hocevar's avatar
Sam Hocevar committed
208
    /* Create thread and wait for its readiness. */
Laurent Aimar's avatar
Laurent Aimar committed
209
    if( vlc_thread_create( p_input, "input", Run,
210
                           VLC_THREAD_PRIORITY_INPUT, VLC_TRUE ) )
Michel Kaempf's avatar
Michel Kaempf committed
211
    {
212
        msg_Err( p_input, "cannot create input thread" );
Laurent Aimar's avatar
Laurent Aimar committed
213 214
        vlc_object_detach( p_input );
        vlc_object_destroy( p_input );
215
        return NULL;
Michel Kaempf's avatar
Michel Kaempf committed
216
    }
217

218
    return p_input;
Michel Kaempf's avatar
Michel Kaempf committed
219 220
}

221
/*****************************************************************************
Sam Hocevar's avatar
 
Sam Hocevar committed
222
 * input_StopThread: mark an input thread as zombie
223
 *****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
224
 * This function should not return until the thread is effectively cancelled.
225
 *****************************************************************************/
Sam Hocevar's avatar
Sam Hocevar committed
226
void input_StopThread( input_thread_t *p_input )
Michel Kaempf's avatar
Michel Kaempf committed
227
{
Laurent Aimar's avatar
Laurent Aimar committed
228 229
    vlc_list_t *p_list;
    int i;
230

Laurent Aimar's avatar
Laurent Aimar committed
231 232
    /* Set die for input */
    p_input->b_die = VLC_TRUE;
233

Laurent Aimar's avatar
Laurent Aimar committed
234 235
    /* We cannot touch p_input fields directly (we can from another thread),
     * so use the vlc_object_find way, it's perfectly safe */
236

Laurent Aimar's avatar
Laurent Aimar committed
237 238 239
    /* Set die for all access */
    p_list = vlc_list_find( p_input, VLC_OBJECT_ACCESS, FIND_CHILD );
    for( i = 0; i < p_list->i_count; i++ )
240
    {
Laurent Aimar's avatar
Laurent Aimar committed
241
        p_list->p_values[i].p_object->b_die = VLC_TRUE;
242
    }
Laurent Aimar's avatar
Laurent Aimar committed
243
    vlc_list_release( p_list );
244

Laurent Aimar's avatar
Laurent Aimar committed
245 246 247
    /* Set die for all stream */
    p_list = vlc_list_find( p_input, VLC_OBJECT_STREAM, FIND_CHILD );
    for( i = 0; i < p_list->i_count; i++ )
248
    {
Laurent Aimar's avatar
Laurent Aimar committed
249
        p_list->p_values[i].p_object->b_die = VLC_TRUE;
250
    }
Laurent Aimar's avatar
Laurent Aimar committed
251
    vlc_list_release( p_list );
252

Laurent Aimar's avatar
Laurent Aimar committed
253 254 255 256 257 258 259
    /* Set die for all demux */
    p_list = vlc_list_find( p_input, VLC_OBJECT_DEMUX, FIND_CHILD );
    for( i = 0; i < p_list->i_count; i++ )
    {
        p_list->p_values[i].p_object->b_die = VLC_TRUE;
    }
    vlc_list_release( p_list );
Michel Kaempf's avatar
Michel Kaempf committed
260

Laurent Aimar's avatar
Laurent Aimar committed
261
    input_ControlPush( p_input, INPUT_CONTROL_SET_DIE, NULL );
Sam Hocevar's avatar
 
Sam Hocevar committed
262 263 264 265 266 267 268 269 270 271
}

/*****************************************************************************
 * 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 */
272
    vlc_thread_join( p_input );
Sam Hocevar's avatar
 
Sam Hocevar committed
273

Laurent Aimar's avatar
Laurent Aimar committed
274 275 276 277 278
    /* Delete input lock (only after thread joined) */
    vlc_mutex_destroy( &p_input->lock_control );

    /* TODO: maybe input_DestroyThread should also delete p_input instead
     * of the playlist but I'm not sure if it's possible */
Michel Kaempf's avatar
Michel Kaempf committed
279 280
}

281
/*****************************************************************************
Laurent Aimar's avatar
Laurent Aimar committed
282
 * Run: main thread loop
283
 *****************************************************************************
284
 * Thread in charge of processing the network packets and demultiplexing.
285 286 287 288
 *
 * TODO:
 *  read subtitle support (XXX take care of spu-delay in the right way).
 *  multi-input support (XXX may be done with subs)
289
 *****************************************************************************/
Laurent Aimar's avatar
Laurent Aimar committed
290
static int Run( input_thread_t *p_input )
Michel Kaempf's avatar
Michel Kaempf committed
291
{
Laurent Aimar's avatar
Laurent Aimar committed
292
    int64_t i_intf_update = 0;
293

Laurent Aimar's avatar
Laurent Aimar committed
294
    /* Signal that the thread is launched */
Sam Hocevar's avatar
Sam Hocevar committed
295 296
    vlc_thread_ready( p_input );

Laurent Aimar's avatar
Laurent Aimar committed
297
    if( Init( p_input ) )
Sam Hocevar's avatar
 
Sam Hocevar committed
298 299
    {
        /* If we failed, wait before we are killed, and exit */
Laurent Aimar's avatar
Laurent Aimar committed
300
        p_input->b_error = VLC_TRUE;
301

Laurent Aimar's avatar
Laurent Aimar committed
302
        Error( p_input );
303 304

        /* Tell we're dead */
Laurent Aimar's avatar
Laurent Aimar committed
305
        p_input->b_dead = VLC_TRUE;
306

Sam Hocevar's avatar
 
Sam Hocevar committed
307
        return 0;
Sam Hocevar's avatar
 
Sam Hocevar committed
308
    }
Michel Kaempf's avatar
Michel Kaempf committed
309

Laurent Aimar's avatar
Laurent Aimar committed
310
    /* Main loop */
Sam Hocevar's avatar
 
Sam Hocevar committed
311 312
    while( !p_input->b_die && !p_input->b_error && !p_input->b_eof )
    {
Laurent Aimar's avatar
Laurent Aimar committed
313 314 315 316
        vlc_bool_t b_force_update = VLC_FALSE;
        int i_ret;
        int i_type;
        vlc_value_t val;
317

Laurent Aimar's avatar
Laurent Aimar committed
318 319
        /* Do the read */
        if( p_input->i_state != PAUSE_S  )
320
        {
Laurent Aimar's avatar
Laurent Aimar committed
321 322 323 324
            if( p_input->i_stop <= 0 || p_input->i_time < p_input->i_stop )
                i_ret=p_input->input.p_demux->pf_demux(p_input->input.p_demux);
            else
                i_ret = 0;  /* EOF */
325

Laurent Aimar's avatar
Laurent Aimar committed
326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345
            if( i_ret > 0 )
            {
                /* TODO */
                if( p_input->input.b_title_demux &&
                    p_input->input.p_demux->info.i_update )
                {
                    UpdateFromDemux( p_input );
                    b_force_update = VLC_TRUE;
                }
                else if( !p_input->input.b_title_demux &&
                          p_input->input.p_access &&
                          p_input->input.p_access->info.i_update )
                {
                    UpdateFromAccess( p_input );
                    b_force_update = VLC_TRUE;
                }
            }
            else if( i_ret == 0 )    /* EOF */
            {
                vlc_value_t repeat;
346

Laurent Aimar's avatar
Laurent Aimar committed
347 348 349 350 351 352 353 354 355 356
                var_Get( p_input, "input-repeat", &repeat );
                if( repeat.i_int == 0 )
                {
                    /* End of file - we do not set b_die because only the
                     * playlist is allowed to do so. */
                    msg_Dbg( p_input, "EOF reached" );
                    p_input->b_eof = VLC_TRUE;
                    p_input->input.b_eof = VLC_TRUE;
                }
                else
357
                {
Laurent Aimar's avatar
Laurent Aimar committed
358 359 360 361 362 363
                    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 );
                    }
364

Laurent Aimar's avatar
Laurent Aimar committed
365 366 367 368 369 370 371 372 373 374 375 376 377 378 379
                    /* Seek to title 0 position 0(start) */
                    val.i_int = 0;
                    input_ControlPush( p_input, INPUT_CONTROL_SET_TITLE, &val );
                    if( p_input->i_start > 0 )
                    {
                        val.i_time = p_input->i_start;
                        input_ControlPush( p_input, INPUT_CONTROL_SET_TIME,
                                           &val );
                    }
                    else
                    {
                        val.f_float = 0.0;
                        input_ControlPush( p_input, INPUT_CONTROL_SET_POSITION,
                                           &val );
                    }
380 381
                }
            }
Laurent Aimar's avatar
Laurent Aimar committed
382 383 384 385
            else if( i_ret < 0 )
            {
                p_input->b_error = VLC_TRUE;
            }
386
        }
Laurent Aimar's avatar
Laurent Aimar committed
387
        else
388
        {
Laurent Aimar's avatar
Laurent Aimar committed
389 390 391
            /* Small wait */
            msleep( 10*1000 );
        }
392

Laurent Aimar's avatar
Laurent Aimar committed
393 394 395 396 397 398 399 400 401 402
        /* Handle control */
        vlc_mutex_lock( &p_input->lock_control );
        ControlReduce( p_input );
        while( !ControlPopNoLock( p_input, &i_type, &val ) )
        {
            msg_Dbg( p_input, "control type=%d", i_type );
            if( Control( p_input, i_type, val ) )
                b_force_update = VLC_TRUE;
        }
        vlc_mutex_unlock( &p_input->lock_control );
403

Laurent Aimar's avatar
Laurent Aimar committed
404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427
        if( b_force_update ||
            i_intf_update < mdate() )
        {
            vlc_value_t val;
            double f_pos;
            int64_t i_time, i_length;
            /* update input status variables */
            if( !demux2_Control( p_input->input.p_demux, DEMUX_GET_POSITION, &f_pos ) )
            {
                val.f_float = (float)f_pos;
                var_Change( p_input, "position", VLC_VAR_SETVALUE, &val, NULL );
            }
            if( !demux2_Control( p_input->input.p_demux, DEMUX_GET_TIME, &i_time ) )
            {
                p_input->i_time = i_time;
                val.i_time = i_time;
                var_Change( p_input, "time", VLC_VAR_SETVALUE, &val, NULL );
            }
            if( !demux2_Control( p_input->input.p_demux, DEMUX_GET_LENGTH, &i_length ) )
            {
                vlc_value_t old_val;
                var_Get( p_input, "length", &old_val );
                val.i_time = i_length;
                var_Change( p_input, "length", VLC_VAR_SETVALUE, &val, NULL );
428

Laurent Aimar's avatar
Laurent Aimar committed
429
                if( old_val.i_time != val.i_time )
430
                {
Laurent Aimar's avatar
Laurent Aimar committed
431 432 433
                    /* TODO */
#if 0
                    char psz_buffer[MSTRTIME_MAX_SIZE];
434

Laurent Aimar's avatar
Laurent Aimar committed
435 436 437 438 439 440 441
                    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 ) );
#endif
442 443
                }
            }
Laurent Aimar's avatar
Laurent Aimar committed
444 445 446

            var_SetBool( p_input, "intf-change", VLC_TRUE );
            i_intf_update = mdate() + I64C(150000);
447
        }
Laurent Aimar's avatar
Laurent Aimar committed
448 449 450 451 452 453 454 455 456 457 458 459
    }

    /* Wait we are asked to die */
    if( !p_input->b_die )
    {
        Error( p_input );
    }

    /* Clean up */
    End( p_input );

    return 0;
460

Laurent Aimar's avatar
Laurent Aimar committed
461 462 463
#if 0
    while( !p_input->b_die && !p_input->b_error && !p_input->b_eof )
    {
464
        if( p_input->stream.p_selected_area->i_seek != NO_SEEK )
Sam Hocevar's avatar
 
Sam Hocevar committed
465
        {
466
            if( p_input->stream.p_selected_area->i_size > 0 )
467
            {
468
                unsigned int i;
469
                mtime_t      i_time;
470 471
                double f = (double)p_input->stream.p_selected_area->i_seek /
                           (double)p_input->stream.p_selected_area->i_size;
472

Christophe Massiot's avatar
Christophe Massiot committed
473
                vlc_mutex_unlock( &p_input->stream.stream_lock );
474
                demux_Control( p_input, DEMUX_SET_POSITION, f );
Christophe Massiot's avatar
Christophe Massiot committed
475
                vlc_mutex_lock( &p_input->stream.stream_lock );
476

477 478 479 480
                /* Escape all decoders for the stream discontinuity they
                 * will encounter. */
                input_EscapeDiscontinuity( p_input );

481 482
                for( i = 0; i < p_input->stream.i_pgrm_number; i++ )
                {
483
                    pgrm_descriptor_t * p_pgrm=p_input->stream.pp_programs[i];
484 485 486 487

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

Laurent Aimar's avatar
Laurent Aimar committed
489
                vlc_mutex_unlock( &p_input->stream.stream_lock );
490 491 492 493 494 495 496 497 498 499 500 501 502 503 504
                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 );
                    }
                }
505 506 507 508 509
                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
510
                vlc_mutex_lock( &p_input->stream.stream_lock );
511
            }
512
            p_input->stream.p_selected_area->i_seek = NO_SEEK;
Sam Hocevar's avatar
 
Sam Hocevar committed
513
        }
514

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

Laurent Aimar's avatar
Laurent Aimar committed
518
        XXXXX
519 520 521

        if( !p_input->b_error && !p_input->b_eof && i_update_next < mdate() )
        {
522 523 524 525
            int i;
            mtime_t i_time;
            mtime_t i_length;
            double  d_pos;
526 527

            /* update input status variables */
528
            if( !demux_Control( p_input, DEMUX_GET_POSITION, &d_pos ) )
529
            {
530
                val.f_float = (float)d_pos;
531 532
                var_Change( p_input, "position", VLC_VAR_SETVALUE, &val, NULL );
            }
533
            if( !demux_Control( p_input, DEMUX_GET_TIME, &i_time ) )
534
            {
535
                val.i_time = i_time;
536 537
                var_Change( p_input, "time", VLC_VAR_SETVALUE, &val, NULL );
            }
538
            if( !demux_Control( p_input, DEMUX_GET_LENGTH, &i_length ) )
539
            {
540 541
                vlc_value_t old_val;
                var_Get( p_input, "length", &old_val );
542
                val.i_time = i_length;
543
                var_Change( p_input, "length", VLC_VAR_SETVALUE, &val, NULL );
544 545 546 547 548 549 550 551 552 553 554
                if( old_val.i_time != val.i_time )
                {
                    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 ) );
                }
555 556
            }

557 558 559 560 561 562 563
            /* 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;
            }

564 565 566 567 568 569
            /* update subs */
            for( i = 0; i < p_input->p_sys->i_sub; i++ )
            {
                subtitle_Demux( p_input->p_sys->sub[i], i_time );
            }

570
            i_update_next = mdate() + I64C(150000);
571
        }
572 573
    }

Sam Hocevar's avatar
 
Sam Hocevar committed
574
    if( p_input->b_error || p_input->b_eof )
575 576 577
    {
        ErrorThread( p_input );
    }
578

579
    EndThread( p_input );
Sam Hocevar's avatar
 
Sam Hocevar committed
580

Sam Hocevar's avatar
 
Sam Hocevar committed
581
    return 0;
Laurent Aimar's avatar
Laurent Aimar committed
582
#endif
583 584
}

585
/*****************************************************************************
Laurent Aimar's avatar
Laurent Aimar committed
586
 * Init: init the input Thread
587
 *****************************************************************************/
Laurent Aimar's avatar
Laurent Aimar committed
588
static int Init( input_thread_t * p_input )
Michel Kaempf's avatar
Michel Kaempf committed
589
{
Laurent Aimar's avatar
Laurent Aimar committed
590 591 592 593 594 595
    char *psz_dup = strdup( p_input->input.p_item->psz_uri );
    char *psz_access = NULL;
    char *psz_demux  = NULL;
    char *psz_path   = NULL;
    char *psz;
    vlc_value_t val;
596

Laurent Aimar's avatar
Laurent Aimar committed
597 598
    /* Open access/stream/demux */
    psz = strchr( psz_dup, ':' );
599
#if defined( WIN32 ) || defined( UNDER_CE )
Laurent Aimar's avatar
Laurent Aimar committed
600
    if( psz - psz_dup == 1 )
601
    {
Laurent Aimar's avatar
Laurent Aimar committed
602
        msg_Warn( p_input, "drive letter %c: found in source string", psz_dup[0] );
Gildas Bazin's avatar
Gildas Bazin committed
603
        psz_path = psz_dup;
Michel Kaempf's avatar
Michel Kaempf committed
604
    }
Christophe Massiot's avatar
Christophe Massiot committed
605
    else
Laurent Aimar's avatar
Laurent Aimar committed
606 607
#endif
    if( psz )
Christophe Massiot's avatar
Christophe Massiot committed
608
    {
Laurent Aimar's avatar
Laurent Aimar committed
609 610 611
        *psz++ = '\0';
        if( psz[0] == '/' && psz[1] == '/' )
            psz += 2;
Xavier Marchesini's avatar
 
Xavier Marchesini committed
612

Laurent Aimar's avatar
Laurent Aimar committed
613
        psz_path = psz;
Sam Hocevar's avatar
 
Sam Hocevar committed
614

Laurent Aimar's avatar
Laurent Aimar committed
615 616
        psz = strchr( psz_dup, '/' );
        if( psz )
Christophe Massiot's avatar
Christophe Massiot committed
617
        {
Laurent Aimar's avatar
Laurent Aimar committed
618 619
            *psz++ = '\0';
            psz_demux = psz;
Christophe Massiot's avatar
Christophe Massiot committed
620
        }
Gildas Bazin's avatar
 
Gildas Bazin committed
621

Laurent Aimar's avatar
Laurent Aimar committed
622
        psz_access = psz_dup;
Sam Hocevar's avatar
 
Sam Hocevar committed
623
    }
Laurent Aimar's avatar
Laurent Aimar committed
624
    else
625
    {
Laurent Aimar's avatar
Laurent Aimar committed
626
        psz_path = psz_dup;
627 628
    }

Laurent Aimar's avatar
Laurent Aimar committed
629 630 631 632 633 634 635 636 637 638 639
    if( psz_access == NULL ) psz_access = "";
    if( psz_demux == NULL )  psz_demux = "";
    if( psz_path == NULL )   psz_path = "";

    msg_Dbg( p_input, "`%s' gives access `%s' demux `%s' path `%s'",
            p_input->input.p_item->psz_uri,
             psz_access, psz_demux, psz_path );

    /* Initialize optional stream output. (before access/demuxer) */
    psz = var_GetString( p_input, "sout" );
    if( *psz )
640
    {
Laurent Aimar's avatar
Laurent Aimar committed
641 642
        p_input->p_sout = sout_NewInstance( p_input, psz );
        if( p_input->p_sout == NULL )
643 644
        {
            msg_Err( p_input, "cannot start stream output instance, aborting" );
Laurent Aimar's avatar
Laurent Aimar committed
645 646
            free( psz );
            free( psz_dup );
647

648 649
            return VLC_EGENERIC;
        }
650
    }
Laurent Aimar's avatar
Laurent Aimar committed
651
    free( psz );
Christophe Massiot's avatar
Christophe Massiot committed
652

Laurent Aimar's avatar
Laurent Aimar committed
653
    /* Create es out */
654
    p_input->p_es_out = input_EsOutNew( p_input );
655 656
    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 );
657

Laurent Aimar's avatar
Laurent Aimar committed
658 659
    /* Try access_demux if no demux given */
    if( *psz_access && *psz_demux == '\0' )
660
    {
Laurent Aimar's avatar
Laurent Aimar committed
661 662 663
        p_input->input.p_demux = demux2_New( p_input, psz_access, psz_demux, psz_path,
                                             NULL, p_input->p_es_out );
    }
664

Laurent Aimar's avatar
Laurent Aimar committed
665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681
    if( p_input->input.p_demux )
    {
        /* Get infos from access_demux */
        demux2_Control( p_input->input.p_demux,
                        DEMUX_GET_PTS_DELAY, &p_input->i_pts_delay );
        p_input->input.b_title_demux = VLC_TRUE;
        if( demux2_Control( p_input->input.p_demux,
                            DEMUX_GET_TITLE_INFO,
                            &p_input->input.title, &p_input->input.i_title ) )
        {
            p_input->input.i_title = 0;
            p_input->input.title   = NULL;
        }
        demux2_Control( p_input->input.p_demux, DEMUX_CAN_CONTROL_PACE,
                        &p_input->input.b_can_pace_control );
        demux2_Control( p_input->input.p_demux, DEMUX_CAN_PAUSE,
                        &p_input->input.b_can_pause );
682 683 684 685 686

        /* FIXME todo
        demux2_Control( p_input->input.p_demux, DEMUX_CAN_SEEK,
                        &val.b_bool );
        */
687
    }
Laurent Aimar's avatar
Laurent Aimar committed
688 689 690 691 692 693 694 695 696 697 698 699 700 701 702
    else
    {
        /* Now try a real access */
        p_input->input.p_access = access2_New( p_input, psz_access, psz_demux, psz_path );

        /* Access failed, URL encoded ? */
        if( p_input->input.p_access == NULL && strchr( psz_path, '%' ) )
        {
            DecodeUrl( psz_path );

            msg_Dbg( p_input, "retying with access `%s' demux `%s' path `%s'",
                     psz_access, psz_demux, psz_path );

            p_input->input.p_access = access2_New( p_input, psz_access, psz_demux, psz_path );
        }
Gildas Bazin's avatar
 
Gildas Bazin committed
703
#ifndef WIN32      /* Remove this gross hack from the win32 build as colons
Laurent Aimar's avatar
Laurent Aimar committed
704
                        * are forbidden in filenames on Win32. */
Gildas Bazin's avatar
 
Gildas Bazin committed
705

Laurent Aimar's avatar
Laurent Aimar committed
706 707 708 709 710 711 712 713 714
        /* Maybe we got something like: /Volumes/toto:titi/gabu.mpg */
        if( p_input->input.p_access == NULL &&
            *psz_access == '\0' && ( *psz_demux || *psz_path ) )
        {
            free( psz_dup );
            psz_dup = strdup( p_input->input.p_item->psz_uri );
            psz_access = "";
            psz_demux = "";
            psz_path = psz_dup;
715

Laurent Aimar's avatar
Laurent Aimar committed
716 717
            p_input->input.p_access = access2_New( p_input, psz_access, psz_demux, psz_path );
        }
Gildas Bazin's avatar
 
Gildas Bazin committed
718
#endif
Laurent Aimar's avatar
Laurent Aimar committed
719 720

        if( p_input->input.p_access == NULL )
721
        {
Laurent Aimar's avatar
Laurent Aimar committed
722 723 724
            msg_Err( p_input, "no suitable access module for `%s'",
                     p_input->input.p_item->psz_uri );
            goto error;
725
        }
726

Laurent Aimar's avatar
Laurent Aimar committed
727 728 729 730 731 732 733
        /* Get infos from access */
        access2_Control( p_input->input.p_access,
                         ACCESS_GET_PTS_DELAY, &p_input->i_pts_delay );
        p_input->input.b_title_demux = VLC_FALSE;
        if( access2_Control( p_input->input.p_access,
                             ACCESS_GET_TITLE_INFO,
                             &p_input->input.title, &p_input->input.i_title ) )
734
        {
Laurent Aimar's avatar
Laurent Aimar committed
735 736 737 738 739 740 741
            p_input->input.i_title = 0;
            p_input->input.title   = NULL;
        }
        access2_Control( p_input->input.p_access, ACCESS_CAN_CONTROL_PACE,
                         &p_input->input.b_can_pace_control );
        access2_Control( p_input->input.p_access, ACCESS_CAN_PAUSE,
                         &p_input->input.b_can_pace_control );
742 743 744
        access2_Control( p_input->input.p_access, ACCESS_CAN_SEEK,
                         &val.b_bool );
        var_Set( p_input, "seekable", val );
Laurent Aimar's avatar
Laurent Aimar committed
745 746 747 748 749 750 751

        /* Create the stream_t */
        p_input->input.p_stream = stream_AccessNew( p_input->input.p_access );
        if( p_input->input.p_stream == NULL )
        {
            msg_Warn( p_input, "cannot create a stream_t from access" );
            goto error;
752
        }
Christophe Massiot's avatar
Christophe Massiot committed
753

Laurent Aimar's avatar
Laurent Aimar committed
754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782
        /* Open a demuxer */
        if( *psz_demux == '\0' && *p_input->input.p_access->psz_demux )
        {
            psz_demux = p_input->input.p_access->psz_demux;
        }
        p_input->input.p_demux = demux2_New( p_input, psz_access, psz_demux, psz_path,
                                             p_input->input.p_stream,
                                             p_input->p_es_out );
        if( p_input->input.p_demux == NULL )
        {
            msg_Err( p_input, "no suitable demux module for `%s/%s://%s'",
                     psz_access, psz_demux, psz_path );
            goto error;
        }

        /* TODO get title from demux */
        if( p_input->input.i_title <= 0 )
        {
            if( demux2_Control( p_input->input.p_demux, DEMUX_GET_TITLE_INFO,
                                &p_input->input.title, &p_input->input.i_title ) )
            {
                p_input->input.i_title = 0;
                p_input->input.title   = NULL;
            }
            else
            {
                p_input->input.b_title_demux = VLC_TRUE;
            }
        }
Christophe Massiot's avatar
Christophe Massiot committed
783
    }
Laurent Aimar's avatar
Laurent Aimar committed
784 785 786
    /* Create global title (for now, just a copy) */
    p_input->i_title = p_input->input.i_title;
    if( p_input->i_title > 0 )
787
    {
Laurent Aimar's avatar
Laurent Aimar committed
788 789 790 791 792 793 794 795 796 797
        int i;
        p_input->title = malloc( sizeof( input_title_t *) * p_input->i_title );
        for( i = 0; i < p_input->i_title; i++ )
        {
            p_input->title[i] = vlc_input_title_Duplicate( p_input->input.title[i] );
        }

        /* Setup variables */
        input_ControlVarNavigation( p_input );
        input_ControlVarTitle( p_input, 0 );
798
    }
Laurent Aimar's avatar
Laurent Aimar committed
799 800 801 802 803 804 805
    /* Global flag */
    p_input->b_can_pace_control = p_input->input.b_can_pace_control;
    p_input->b_can_pause        = p_input->input.b_can_pause;

    /* Fix pts delay */
    if( p_input->i_pts_delay <= 0 )
        p_input->i_pts_delay = DEFAULT_PTS_DELAY;
806

Gildas Bazin's avatar
 
Gildas Bazin committed
807 808
    /* If the desynchronisation requested by the user is < 0, we need to
     * cache more data. */
Gildas Bazin's avatar
 
Gildas Bazin committed
809 810 811
    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
812

Laurent Aimar's avatar
Laurent Aimar committed
813 814 815 816
    /* 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;
Sam Hocevar's avatar
 
Sam Hocevar committed
817

Laurent Aimar's avatar
Laurent Aimar committed
818
    /* TODO: check meta data from users */
819

Laurent Aimar's avatar
Laurent Aimar committed
820
    /* TODO: get meta data from demuxer */
821

Laurent Aimar's avatar
Laurent Aimar committed
822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837
    /* Init length */
    if( !demux2_Control( p_input->input.p_demux, DEMUX_GET_LENGTH, &val.i_time ) && val.i_time > 0 )
    {
        var_Change( p_input, "length", VLC_VAR_SETVALUE, &val, NULL );
        /* TODO update playlist meta data */
    }
    /* Start time*/
    /* Set start time */
    p_input->i_start = (int64_t)var_GetInteger( p_input, "start-time" ) *
                       I64C(1000000);
    p_input->i_stop  = (int64_t)var_GetInteger( p_input, "stop-time" ) *
                       I64C(1000000);

    if( p_input->i_start > 0 )
    {
        if( p_input->i_start >= val.i_time )
838
        {
Laurent Aimar's avatar
Laurent Aimar committed
839
            msg_Warn( p_input, "invalid start-time ignored" );
840
        }
Laurent Aimar's avatar
Laurent Aimar committed
841
        else
842
        {
Laurent Aimar's avatar
Laurent Aimar committed
843 844 845 846 847 848 849
            vlc_value_t s;

            msg_Dbg( p_input, "start-time: %ds",
                     (int)( p_input->i_start / I64C(1000000) ) );

            s.i_time = p_input->i_start;
            input_ControlPush( p_input, INPUT_CONTROL_SET_TIME, &s );
850
        }
Laurent Aimar's avatar
Laurent Aimar committed
851 852 853 854 855
    }
    if( p_input->i_stop > 0 && p_input->i_stop <= p_input->i_start )
    {
        msg_Warn( p_input, "invalid stop-time ignored" );
        p_input->i_stop = 0;
856 857
    }

Sam Hocevar's avatar
 
Sam Hocevar committed
858

Laurent Aimar's avatar
Laurent Aimar committed
859
    /* TODO: do subtitle loading */
860

Laurent Aimar's avatar
Laurent Aimar committed
861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885

    /* Set up es_out */
    es_out_Control( p_input->p_es_out, ES_OUT_SET_ACTIVE, VLC_TRUE );
    val.b_bool =  VLC_FALSE;
    if( p_input->p_sout )
    {
        var_Get( p_input, "sout-all", &val );
    }
    es_out_Control( p_input->p_es_out, ES_OUT_SET_MODE,
                    val.b_bool ? ES_OUT_MODE_ALL : ES_OUT_MODE_AUTO );

    /* TODO select forced subs */
#if 0
    if( p_sub_toselect )
    {
        es_out_Control( p_input->p_es_out, ES_OUT_SET_ES,
                        p_sub_toselect->p_es, VLC_TRUE );
    }
#endif

    if( p_input->p_sout )
    {
        if( p_input->p_sout->i_out_pace_nocontrol > 0 )
        {
            p_input->b_out_pace_control = VLC_FALSE;
886
        }
Laurent Aimar's avatar
Laurent Aimar committed
887 888 889 890 891 892
        else
        {
            p_input->b_out_pace_control = VLC_TRUE;
        }
        msg_Dbg( p_input, "starting in %s mode",
                 p_input->b_out_pace_control ? "asynch" : "synch" );
893 894
    }

Laurent Aimar's avatar
Laurent Aimar committed
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 936 937 938 939 940 941 942
    msg_Dbg( p_input, "`%s' sucessfully opened",
             p_input->input.p_item->psz_uri );

    /* initialization is complete */
    p_input->i_state = PLAYING_S;

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

    return VLC_SUCCESS;

error:
    if( p_input->input.p_demux )
        demux2_Delete( p_input->input.p_demux );

    if( p_input->input.p_stream )
        stream_AccessDelete( p_input->input.p_stream );

    if( p_input->input.p_access )
        access2_Delete( p_input->input.p_access );

    if( p_input->p_es_out )
        input_EsOutDelete( p_input->p_es_out );

    if( p_input->p_sout )
        sout_DeleteInstance( p_input->p_sout );

    /* Mark them deleted */
    p_input->input.p_demux = NULL;
    p_input->input.p_stream = NULL;
    p_input->input.p_access = NULL;
    p_input->p_es_out = NULL;
    p_input->p_sout = NULL;

    return VLC_EGENERIC;

#if 0
    vlc_meta_t *p_meta = NULL, *p_meta_user = NULL;
//    float f_fps;
    double f_fps;
    mtime_t i_length;

    FIXME
    p_input->input.i_cr_average = config_GetInt( p_input, "cr-average" );
    p_input->stream.control.i_status = INIT_S;
    p_input->stream.control.i_rate = DEFAULT_RATE;


943 944 945 946 947
    /* 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;

948 949 950 951 952 953 954 955 956 957 958 959 960 961
    /* 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 );
Laurent Aimar's avatar
Laurent Aimar committed
962
        if( *val.psz_string )
963
            vlc_meta_Add( p_meta_user, VLC_META_TITLE, val.psz_string );
Laurent Aimar's avatar
Laurent Aimar committed
964
        free( val.psz_string );
965
        var_Get( p_input, "meta-author", &val );
Laurent Aimar's avatar
Laurent Aimar committed
966
        if( *val.psz_string )
967
            vlc_meta_Add( p_meta_user, VLC_META_AUTHOR, val.psz_string );
Laurent Aimar's avatar
Laurent Aimar committed
968
        free( val.psz_string );
969
        var_Get( p_input, "meta-artist", &val );
Laurent Aimar's avatar
Laurent Aimar committed
970
        if( *val.psz_string )
971
            vlc_meta_Add( p_meta_user, VLC_META_ARTIST, val.psz_string );
Laurent Aimar's avatar
Laurent Aimar committed
972
        free( val.psz_string );
973
        var_Get( p_input, "meta-genre", &val );
Laurent Aimar's avatar
Laurent Aimar committed
974
        if( *val.psz_string )
975
            vlc_meta_Add( p_meta_user, VLC_META_GENRE, val.psz_string );
Laurent Aimar's avatar
Laurent Aimar committed
976
        free( val.psz_string );
977
        var_Get( p_input, "meta-copyright", &val );
Laurent Aimar's avatar
Laurent Aimar committed
978
        if( *val.psz_string )
979
            vlc_meta_Add( p_meta_user, VLC_META_COPYRIGHT, val.psz_string );
Laurent Aimar's avatar
Laurent Aimar committed
980
        free( val.psz_string );
981
        var_Get( p_input, "meta-description", &val );
Laurent Aimar's avatar
Laurent Aimar committed
982
        if( *val.psz_string )
983
            vlc_meta_Add( p_meta_user, VLC_META_DESCRIPTION, val.psz_string );
Laurent Aimar's avatar
Laurent Aimar committed
984
        free( val.psz_string );
985
        var_Get( p_input, "meta-date", &val );
Laurent Aimar's avatar
Laurent Aimar committed
986
        if( *val.psz_string )
987
            vlc_meta_Add( p_meta_user, VLC_META_DATE, val.psz_string );
Laurent Aimar's avatar
Laurent Aimar committed
988
        free( val.psz_string );
989
        var_Get( p_input, "meta-url", &val );
Laurent Aimar's avatar
Laurent Aimar committed
990
        if( *val.psz_string )
991
            vlc_meta_Add( p_meta_user, VLC_META_URL, val.psz_string );
Laurent Aimar's avatar
Laurent Aimar committed
992
        free( val.psz_string );
993 994 995 996 997
    }

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

1001 1002 1003 1004
        /* 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 );

1005
        msg_Dbg( p_input, "meta informations:" );
1006
        if( p_meta->i_meta > 0 )
1007
        {
1008
            for( i = 0; i < p_meta->i_meta; i++ )
1009
            {
1010 1011
                msg_Dbg( p_input, "  - '%s' = '%s'", _(p_meta->name[i]),
                         p_meta->value[i] );
1012 1013 1014 1015
                if( !strcmp( p_meta->name[i], VLC_META_TITLE ) &&
                    p_meta->value[i] )
                    input_Control( p_input, INPUT_SET_NAME, p_meta->value[i] );

1016
                if( !strcmp( p_meta->name[i], VLC_META_AUTHOR ) )
1017 1018 1019 1020 1021
                    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] );
1022 1023
            }
        }
1024
        for( i = 0; i < p_meta->i_track; i++ )
1025
        {
1026
            vlc_meta_t *tk = p_meta->track[i];
1027 1028 1029 1030 1031 1032 1033 1034 1035 1036
            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++ )
                {
1037 1038
                    msg_Dbg( p_input, "     - '%s' = '%s'", _(tk->name[j]),
                             tk->value[j] );
1039 1040 1041

                    input_Control( p_input, INPUT_ADD_INFO, psz_cat,
                                   _(tk->name[j]), "%s", tk->value[j] );
1042 1043 1044 1045
                }
            }
        }

1046 1047
        if( p_input->stream.p_sout && p_input->stream.p_sout->p_meta == NULL )
        {