input.c 61.3 KB
Newer Older
1 2
/*****************************************************************************
 * input.c: input thread
3
 *****************************************************************************
4
 * Copyright (C) 1998-2004 VideoLAN
5
 * $Id$
6
 *
7
 * Authors: Christophe Massiot <massiot@via.ecp.fr>
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>
29

30
#include <vlc/vlc.h>
31
#include <vlc/input.h>
32
#include <vlc/decoder.h>
33
#include <vlc/vout.h>
34

35
#include "input_internal.h"
36

37 38
#include "stream_output.h"

39
#include "vlc_interface.h"
40
#include "vlc_meta.h"
41

42
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
43
 * Local prototypes
44
 *****************************************************************************/
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

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.
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
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)
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

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

139
    /* Parse input options */
140 141
    vlc_mutex_lock( &p_item->lock );
    for( i = 0; i < p_item->i_options; i++ )
142
    {
143 144
        msg_Dbg( p_input, "option: %s", p_item->ppsz_options[i] );
        ParseOption( p_input, p_item->ppsz_options[i] );
145
    }
146
    vlc_mutex_unlock( &p_item->lock );
147

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

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

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 );
    }
203
#endif
Gildas Bazin's avatar
Gildas Bazin committed
204

205
    /* Now we can attach our new input */
206
    vlc_object_attach( p_input, p_parent );
207

Sam Hocevar's avatar
Sam Hocevar committed
208
    /* Create thread and wait for its readiness. */
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" );
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
/*****************************************************************************
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
{
228 229
    vlc_list_t *p_list;
    int i;
230

231 232
    /* Set die for input */
    p_input->b_die = VLC_TRUE;
233

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

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
    {
241
        p_list->p_values[i].p_object->b_die = VLC_TRUE;
242
    }
243
    vlc_list_release( p_list );
244

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
    {
249
        p_list->p_values[i].p_object->b_die = VLC_TRUE;
250
    }
251
    vlc_list_release( p_list );
252

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

261
    input_ControlPush( p_input, INPUT_CONTROL_SET_DIE, NULL );
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 );
273

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
/*****************************************************************************
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
 *****************************************************************************/
290
static int Run( input_thread_t *p_input )
Michel Kaempf's avatar
Michel Kaempf committed
291
{
292
    int64_t i_intf_update = 0;
293

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

297
    if( Init( p_input ) )
298 299
    {
        /* If we failed, wait before we are killed, and exit */
300
        p_input->b_error = VLC_TRUE;
301

302
        Error( p_input );
303 304

        /* Tell we're dead */
305
        p_input->b_dead = VLC_TRUE;
306

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

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

318 319
        /* Do the read */
        if( p_input->i_state != PAUSE_S  )
320
        {
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

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

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
                {
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

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
                }
            }
382 383 384 385
            else if( i_ret < 0 )
            {
                p_input->b_error = VLC_TRUE;
            }
386
        }
387
        else
388
        {
389 390 391
            /* Small wait */
            msleep( 10*1000 );
        }
392

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

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

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

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
                }
            }
444 445 446

            var_SetBool( p_input, "intf-change", VLC_TRUE );
            i_intf_update = mdate() + I64C(150000);
447
        }
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

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 )
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;
513
        }
514

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

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
    }

574
    if( p_input->b_error || p_input->b_eof )
575 576 577
    {
        ErrorThread( p_input );
    }
578

579
    EndThread( p_input );
580

581
    return 0;
582
#endif
583 584
}

585
/*****************************************************************************
586
 * Init: init the input Thread
587
 *****************************************************************************/
588
static int Init( input_thread_t * p_input )
Michel Kaempf's avatar
Michel Kaempf committed
589
{
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

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

613
        psz_path = psz;
614

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

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

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
    {
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" );
645 646
            free( psz );
            free( psz_dup );
647

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

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

658 659
    /* Try access_demux if no demux given */
    if( *psz_access && *psz_demux == '\0' )
660
    {
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

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
    }
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 );
        }
703
#ifndef WIN32      /* Remove this gross hack from the win32 build as colons
704
                        * are forbidden in filenames on Win32. */
705

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

716 717
            p_input->input.p_access = access2_New( p_input, psz_access, psz_demux, psz_path );
        }
718
#endif
719 720

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

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
        {
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 );
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

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
    }
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
    {
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
    }
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

807 808
    /* If the desynchronisation requested by the user is < 0, we need to
     * cache more data. */
809 810 811
    var_Get( p_input, "audio-desync", &val );
    if( val.i_int < 0 )
        p_input->i_pts_delay -= (val.i_int * 1000);
812

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;
817

818
    /* TODO: check meta data from users */
819

820
    /* TODO: get meta data from demuxer */
821

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
        {
839
            msg_Warn( p_input, "invalid start-time ignored" );
840
        }
841
        else
842
        {
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
        }
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
    }

858

859
    /* TODO: do subtitle loading */
860

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
        }
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
    }

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 );
962
        if( *val.psz_string )
963
            vlc_meta_Add( p_meta_user, VLC_META_TITLE, val.psz_string );
964
        free( val.psz_string );
965
        var_Get( p_input, "meta-author", &val );
966
        if( *val.psz_string )
967
            vlc_meta_Add( p_meta_user, VLC_META_AUTHOR, val.psz_string );
968
        free( val.psz_string );
969
        var_Get( p_input, "meta-artist", &val );
970
        if( *val.psz_string )
971
            vlc_meta_Add( p_meta_user, VLC_META_ARTIST, val.psz_string );
972
        free( val.psz_string );
973
        var_Get( p_input, "meta-genre", &val );
974
        if( *val.psz_string )
975
            vlc_meta_Add( p_meta_user, VLC_META_GENRE, val.psz_string );
976
        free( val.psz_string );
977
        var_Get( p_input, "meta-copyright", &val );
978
        if( *val.psz_string )
979
            vlc_meta_Add( p_meta_user, VLC_META_COPYRIGHT, val.psz_string );
980
        free( val.psz_string );
981
        var_Get( p_input, "meta-description", &val );
982
        if( *val.psz_string )
983
            vlc_meta_Add( p_meta_user, VLC_META_DESCRIPTION, val.psz_string );
984
        free( val.psz_string );
985
        var_Get( p_input, "meta-date", &val );
986
        if( *val.psz_string )
987
            vlc_meta_Add( p_meta_user, VLC_META_DATE, val.psz_string );
988
        free( val.psz_string );
989
        var_Get( p_input, "meta-url", &val );
990
        if( *val.psz_string )
991
            vlc_meta_Add( p_meta_user, VLC_META_URL, val.psz_string );
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 )
        {
1048
            p_input->stream.p_sout->p_meta = p_meta;
1049 1050 1051
        }
        else
        {
1052
            vlc_meta_Delete( p_meta );
1053
        }
1054
    }
1055
    if( p_meta_user ) vlc_meta_Delete( p_meta_user );
1056

1057 1058 1059
    /* Get length */
    if( !demux_Control( p_input, DEMUX_GET_LENGTH, &i_length ) &&
        i_length > 0 )
Sigmund Augdal Helberg's avatar
Sigmund Augdal Helberg committed
1060
    {
1061 1062 1063 1064 1065 1066 1067 1068
        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 ) );
1069 1070 1071 1072 1073

        /* Set start time */
        var_Get( p_input, "start-time", &val );
        if(  val.i_int > 0 )
        {
1074
            double f_pos = val.i_int * I64C(1000000) / (double)i_length;
1075 1076 1077

            if( f_pos >= 1.0 )
            {
1078 1079
                msg_Warn( p_input, "invalid start-time, ignored (start-time "
                          ">= media length)" );
1080 1081 1082 1083 1084 1085 1086 1087 1088
            }
            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 );
            }
        }
1089
    }
1090 1091

    /* Get fps */
1092 1093
    if( demux_Control( p_input, DEMUX_GET_FPS, &f_fps ) || f_fps < 0.1 )
    {
1094
        i_microsecondperframe = 0;
1095 1096 1097 1098 1099 1100
    }
    else
    {
        i_microsecondperframe = (int64_t)( (double)1000000.0 / (double)f_fps );
    }

1101
    /* Look for and add subtitle files */
1102 1103 1104
    var_Get( p_input, "sub-file", &val );
    if( val.psz_string && *val.psz_string )
    {
1105
        subtitle_demux_t *p_sub;
Laurent Aimar's avatar
Laurent Aimar committed
1106 1107

        msg_Dbg( p_input, "force subtitle: %s", val.psz_string );
Clément Stenac's avatar
Clément Stenac committed
1108
        if( ( p_sub = subtitle_New( p_input, strdup(val.psz_string),
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
1109
                                    i_microsecondperframe ) ) )
1110
        {
1111
            p_sub_toselect = p_sub;
1112 1113 1114
            TAB_APPEND( p_input->p_sys->i_sub, p_input->p_sys->sub, p_sub );
        }
    }
1115
    psz_sub_file = val.psz_string;
1116

1117
    var_Get( p_input, "sub-autodetect-file", &val );
1118
    var_Get( p_input, "sub-autodetect-path", &val1 );
1119
    if( val.b_bool )
1120
    {
1121
        subtitle_demux_t *p_sub;
1122
        int i;
1123
        char **tmp = subtitles_Detect( p_input, val1.psz_string, p_input->psz_name );
1124
        char **tmp2 = tmp;
1125
        for( i = 0; *tmp2 != NULL; i++ )
1126
        {
1127
            if( psz_sub_file == NULL || strcmp( psz_sub_file, *tmp2 ) )
1128
            {
1129 1130 1131
                if( ( p_sub = subtitle_New( p_input, *tmp2,
                                            i_microsecondperframe ) ) )
                {
1132 1133
                    TAB_APPEND( p_input->p_sys->i_sub, p_input->p_sys->sub,
                                p_sub );
1134
                }
1135
            }
1136
            free( *tmp2++ );
1137
        }
1138
        free( tmp );
1139
        free( val1.psz_string );
1140
    }
1141
    if( psz_sub_file ) free( psz_sub_file );
1142

1143
    es_out_Control( p_input->p_es_out, ES_OUT_SET_ACTIVE, VLC_TRUE );
1144 1145 1146 1147 1148 1149 1150
    val.b_bool =  VLC_FALSE;
    if( p_input->stream.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 );
1151 1152
    if( p_sub_toselect )
    {
Clément Stenac's avatar
Clément Stenac committed
1153