input.c 14.5 KB
Newer Older
1 2
/*****************************************************************************
 * input.c: input thread
Michel Kaempf's avatar
Michel Kaempf committed
3 4
 * Read an MPEG2 stream, demultiplex and parse it before sending it to
 * decoders.
5 6
 *****************************************************************************
 * Copyright (C) 1998, 1999, 2000 VideoLAN
7
 * $Id: input.c,v 1.62 2000/12/21 14:18:15 massiot Exp $
8
 *
9
 * Authors: 
10 11 12 13 14
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
15
 * 
16 17
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 19
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
20
 *
21 22 23
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
24
 *****************************************************************************/
Michel Kaempf's avatar
Michel Kaempf committed
25

26
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
27
 * Preamble
28
 *****************************************************************************/
29 30
#include "defs.h"

31 32 33 34 35 36 37
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
Michel Kaempf's avatar
Michel Kaempf committed
38

39 40 41 42
#ifdef STATS
#   include <sys/times.h>
#endif

Michel Kaempf's avatar
Michel Kaempf committed
43
#include "config.h"
44 45
#include "common.h"
#include "threads.h"
Michel Kaempf's avatar
Michel Kaempf committed
46
#include "mtime.h"
47

48
#include "intf_msg.h"
49

50 51 52
#include "stream_control.h"
#include "input_ext-intf.h"
#include "input_ext-dec.h"
Michel Lespinasse's avatar
Yop,  
Michel Lespinasse committed
53

54
#include "input.h"
Michel Kaempf's avatar
Michel Kaempf committed
55

56
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
57
 * Local prototypes
58
 *****************************************************************************/
59
static void RunThread   ( input_thread_t *p_input );
60
static void InitThread  ( input_thread_t *p_input );
61 62
static void ErrorThread ( input_thread_t *p_input );
static void EndThread   ( input_thread_t *p_input );
63 64
static void NetworkOpen ( input_thread_t *p_input );
static void FileOpen    ( input_thread_t *p_input );
Michel Kaempf's avatar
Michel Kaempf committed
65

66
/*****************************************************************************
67
 * input_CreateThread: creates a new input thread
68
 *****************************************************************************
69 70 71 72
 * This function creates a new input, and returns a pointer
 * to its description. On error, it returns NULL.
 * If pi_status is NULL, then the function will block until the thread is ready.
 * If not, it will be updated using one of the THREAD_* constants.
73
 *****************************************************************************/
74
input_thread_t *input_CreateThread ( input_config_t * p_config, int *pi_status )
Michel Kaempf's avatar
Michel Kaempf committed
75
{
76 77 78
    input_thread_t *    p_input;                        /* thread descriptor */
    int                 i_status;                           /* thread status */

79 80 81 82
    /* Allocate descriptor */
    intf_DbgMsg("\n");
    p_input = (input_thread_t *)malloc( sizeof(input_thread_t) );
    if( p_input == NULL )
Michel Kaempf's avatar
Michel Kaempf committed
83
    {
84 85
        intf_ErrMsg("error: %s\n", strerror(errno));
        free( p_config );
Michel Kaempf's avatar
Michel Kaempf committed
86 87
        return( NULL );
    }
88 89 90 91

    /* Initialize thread properties */
    p_input->b_die              = 0;
    p_input->b_error            = 0;
92
    /* I have never understood that stuff --Meuuh */
93 94
    p_input->pi_status          = (pi_status != NULL) ? pi_status : &i_status;
    *p_input->pi_status         = THREAD_CREATE;
95
    p_input->p_config = p_config;
Michel Kaempf's avatar
Michel Kaempf committed
96

97
    /* Initialize stream description */
98 99 100 101
    p_input->pp_es = NULL;
    p_input->pp_selected_es = NULL;
    p_input->i_es_number = 0;
    p_input->i_selected_es_number = 0;
102
    p_input->stream.i_pgrm_number = 0;
Michel Kaempf's avatar
Michel Kaempf committed
103

104 105 106 107 108 109 110
    /* Initialize stream control properties. */
    p_input->stream.control.i_status = PLAYING_S;
    p_input->stream.control.i_rate = DEFAULT_RATE;
    p_input->stream.control.i_ref_sysdate = 0;
    p_input->stream.control.i_ref_clock = 0;
    p_input->stream.control.b_mute = 0;
    p_input->stream.control.b_bw = 0;
Michel Kaempf's avatar
Michel Kaempf committed
111 112

    /* Create thread and set locks. */
113 114 115 116
    vlc_mutex_init( &p_input->stream.stream_lock );
    vlc_mutex_init( &p_input->stream.control.control_lock );
    if( vlc_thread_create( &p_input->thread_id, "input", (void *) RunThread,
                           (void *) p_input ) )
Michel Kaempf's avatar
Michel Kaempf committed
117
    {
118
        intf_ErrMsg("error: %s\n", strerror(errno) );
Michel Kaempf's avatar
Michel Kaempf committed
119
        free( p_input );
120
        free( p_config );
Michel Kaempf's avatar
Michel Kaempf committed
121 122
        return( NULL );
    }
123

124 125 126 127
    /* If status is NULL, wait until the thread is created */
    if( pi_status == NULL )
    {
        do
128
        {
129
            msleep( THREAD_SLEEP );
130
        } while( (i_status != THREAD_READY) && (i_status != THREAD_ERROR)
131 132 133
                && (i_status != THREAD_FATAL) );
        if( i_status != THREAD_READY )
        {
134 135
            return( NULL );
        }
136
    }
Michel Kaempf's avatar
Michel Kaempf committed
137 138 139
    return( p_input );
}

140
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
141
 * input_DestroyThread: mark an input thread as zombie
142
 *****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
143
 * This function should not return until the thread is effectively cancelled.
144
 *****************************************************************************/
145
void input_DestroyThread( input_thread_t *p_input, int *pi_status )
Michel Kaempf's avatar
Michel Kaempf committed
146
{
147
    int         i_status;                                   /* thread status */
148 149 150

    /* Set status */
    p_input->pi_status = (pi_status != NULL) ? pi_status : &i_status;
151 152
    *p_input->pi_status = THREAD_DESTROY;

153 154
    /* Request thread destruction */
    p_input->b_die = 1;
Michel Kaempf's avatar
Michel Kaempf committed
155

156 157 158 159 160 161
    /* If status is NULL, wait until thread has been destroyed */
    if( pi_status == NULL )
    {
        do
        {
            msleep( THREAD_SLEEP );
162 163
        } while ( (i_status != THREAD_OVER) && (i_status != THREAD_ERROR)
                  && (i_status != THREAD_FATAL) );
164
    }
Michel Kaempf's avatar
Michel Kaempf committed
165 166
}

167
/*****************************************************************************
168
 * RunThread: main thread loop
169
 *****************************************************************************
170
 * Thread in charge of processing the network packets and demultiplexing.
171
 *****************************************************************************/
172
static void RunThread( input_thread_t *p_input )
Michel Kaempf's avatar
Michel Kaempf committed
173
{
174 175
    data_packet_t *         pp_packets[INPUT_READ_ONCE];
    int                     i_error, i;
Michel Kaempf's avatar
Michel Kaempf committed
176

177
    InitThread( p_input );
Michel Kaempf's avatar
Michel Kaempf committed
178

179 180 181 182
    while( !p_input->b_die && !p_input->b_error )
    {
#ifdef STATS
        p_input->c_loops++;
Michel Kaempf's avatar
Michel Kaempf committed
183 184
#endif

185 186 187
        vlc_mutex_lock( &p_input->stream.control.control_lock );
        if( p_input->stream.control.i_status == BACKWARD_S
             && p_input->p_plugin->pf_rewind != NULL )
Sam Hocevar's avatar
Sam Hocevar committed
188
        {
189 190
            p_input->p_plugin->pf_rewind( p_input );
            /* FIXME: probably don't do it every loop, but when ? */
Michel Kaempf's avatar
Michel Kaempf committed
191
        }
192
        vlc_mutex_unlock( &p_input->stream.control.control_lock );
Sam Hocevar's avatar
Sam Hocevar committed
193

194 195 196 197
        i_error = p_input->p_plugin->pf_read( p_input, pp_packets );

        /* Demultiplex read packets. */
        for( i = 0; i < INPUT_READ_ONCE && pp_packets[i] != NULL; i++ )
Sam Hocevar's avatar
Sam Hocevar committed
198
        {
199 200
            p_input->p_plugin->pf_demux( p_input, pp_packets[i] );
        }
201

202 203 204
        if( i_error )
        {
            if( i_error == 1 )
Sam Hocevar's avatar
Sam Hocevar committed
205
            {
206 207 208
                /* End of file */
                intf_WarnMsg( 1, "End of file reached" );
                /* FIXME: don't treat that as an error */
Sam Hocevar's avatar
Sam Hocevar committed
209
            }
210
            p_input->b_error = 1;
211 212 213
        }
    }

214 215 216 217
    if( p_input->b_error )
    {
        ErrorThread( p_input );
    }
218

219 220
    EndThread( p_input );
    intf_DbgMsg("Thread end");
221 222
}

223
/*****************************************************************************
224
 * InitThread: init the input thread
225
 *****************************************************************************/
226 227
input_capabilities_t * PSKludge( void );
static void InitThread( input_thread_t * p_input )
Michel Kaempf's avatar
Michel Kaempf committed
228
{
229 230 231
    /* Initialize default settings for spawned decoders */
    p_input->p_default_aout     = p_input->p_config->p_default_aout;
    p_input->p_default_vout     = p_input->p_config->p_default_vout;
Michel Kaempf's avatar
Michel Kaempf committed
232 233

#ifdef STATS
234 235 236 237 238 239
    /* Initialize statistics */
    p_input->c_loops                    = 0;
    p_input->c_bytes                    = 0;
    p_input->c_payload_bytes            = 0;
    p_input->c_packets_read             = 0;
    p_input->c_packets_trashed          = 0;
Michel Kaempf's avatar
Michel Kaempf committed
240
#endif
Sam Hocevar's avatar
Sam Hocevar committed
241

242 243 244 245 246 247 248 249
    /* Use the appropriate input method */
    switch( p_input->p_config->i_method )
    {
    case INPUT_METHOD_FILE:                                  /* file methods */
        FileOpen( p_input );
        break;
    case INPUT_METHOD_VLAN_BCAST:                     /* vlan network method */
/*        if( !p_main->b_vlans )
Michel Kaempf's avatar
Michel Kaempf committed
250
        {
251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266
            intf_ErrMsg("error: vlans are not activated\n");
            free( p_input );
            return( NULL );
        } */ /* la-lala */
        /* ... pass through */
    case INPUT_METHOD_UCAST:                              /* network methods */
    case INPUT_METHOD_MCAST:
    case INPUT_METHOD_BCAST:
        NetworkOpen( p_input );
        break;
#ifdef DEBUG
    default:
        intf_ErrMsg("Unknow input method");
        free( p_input->p_config );
        p_input->b_error = 1;
        break;
Sam Hocevar's avatar
Sam Hocevar committed
267
#endif
Michel Kaempf's avatar
Michel Kaempf committed
268
    }
269 270 271 272 273 274 275 276

    free( p_input->p_config );

    /* Probe plugin (FIXME: load plugins before & write this) */
    p_input->p_plugin = PSKludge();
    p_input->p_plugin->pf_init( p_input );

    *p_input->pi_status = THREAD_READY;
Michel Kaempf's avatar
Michel Kaempf committed
277 278
}

279
/*****************************************************************************
280
 * ErrorThread: RunThread() error loop
281
 *****************************************************************************
282
 * This function is called when an error occured during thread main's loop.
283
 *****************************************************************************/
284
static void ErrorThread( input_thread_t *p_input )
Michel Kaempf's avatar
Michel Kaempf committed
285
{
286
    while( !p_input->b_die )
Michel Kaempf's avatar
Michel Kaempf committed
287
    {
288 289
        /* Sleep a while */
        msleep( INPUT_IDLE_SLEEP );
Michel Kaempf's avatar
Michel Kaempf committed
290 291 292
    }
}

293
/*****************************************************************************
294
 * EndThread: end the input thread
295
 *****************************************************************************/
296
static void EndThread( input_thread_t * p_input )
297
{
298 299
    int *       pi_status;                                  /* thread status */
    int         i_es_loop;                                       /* es index */
300

301 302 303
    /* Store status */
    pi_status = p_input->pi_status;
    *pi_status = THREAD_END;
Sam Hocevar's avatar
Sam Hocevar committed
304

305 306 307 308 309 310 311 312 313 314
#ifdef STATS
    {
        struct tms cpu_usage;
        times( &cpu_usage );

        intf_Msg("input stats: cpu usage (user: %d, system: %d)\n",
                 cpu_usage.tms_utime, cpu_usage.tms_stime);
    }
#endif

315
    /* Destroy all decoder threads */
316
    for( i_es_loop = 0; i_es_loop < p_input->i_selected_es_number;
317
         i_es_loop++ )
318
    {
319 320 321 322 323 324 325 326 327
        decoder_fifo_t *    p_decoder_fifo;

        p_decoder_fifo = p_input->pp_selected_es[i_es_loop]->p_decoder_fifo;
        p_decoder_fifo->b_die = 1;

        /* Make sure the thread leaves the NextDataPacket() function */
        vlc_mutex_lock( &p_decoder_fifo->data_lock);
        vlc_cond_signal( &p_decoder_fifo->data_wait );
        vlc_mutex_unlock( &p_decoder_fifo->data_lock );
328

329 330
        /* Waiting for the thread to exit */
        vlc_thread_join( p_input->pp_selected_es[i_es_loop]->thread_id );
331 332 333 334 335 336 337 338

        /* Freeing all packets still in the decoder fifo. */
        while( !DECODER_FIFO_ISEMPTY( *p_decoder_fifo ) )
        {
            p_decoder_fifo->pf_delete_pes( p_decoder_fifo->p_packets_mgt,
                                     DECODER_FIFO_START( *p_decoder_fifo ) );
            DECODER_FIFO_INCSTART( *p_decoder_fifo );
        }
339
        free( p_input->pp_selected_es[i_es_loop]->p_decoder_fifo );
Sam Hocevar's avatar
Sam Hocevar committed
340 341
    }

342
    /* Free demultiplexer's data */
343 344 345 346 347 348 349 350
    p_input->p_plugin->pf_end( p_input );
    free( p_input->p_plugin );

    /* Free input structures */
    input_EndStream( p_input );
    free( p_input->pp_es );
    free( p_input->pp_selected_es );
    free( p_input );
351

352 353
    /* Update status */
    *pi_status = THREAD_OVER;
Sam Hocevar's avatar
Sam Hocevar committed
354
}
355

Sam Hocevar's avatar
Sam Hocevar committed
356
/*****************************************************************************
357
 * NetworkOpen : open a network socket descriptor
Sam Hocevar's avatar
Sam Hocevar committed
358
 *****************************************************************************/
359
static void NetworkOpen( input_thread_t * p_input )
Sam Hocevar's avatar
Sam Hocevar committed
360
{
361
    /* straight copy & paste of input_network.c of input-I */
362

363 364 365 366
    /* We cannot rewind nor lseek() */
    p_input->stream.b_seekable = 0;
    /* We cannot control the pace */
    p_input->stream.b_pace_control = 0;
367 368
}

369
/*****************************************************************************
370
 * FileOpen : open a file descriptor
371
 *****************************************************************************/
372
static void FileOpen( input_thread_t * p_input )
Michel Kaempf's avatar
Michel Kaempf committed
373
{
374
    struct stat         stat_info;
Michel Kaempf's avatar
Michel Kaempf committed
375

376
#define p_config    p_input->p_config
Michel Kaempf's avatar
Michel Kaempf committed
377

378
    if( !strncmp( p_config->p_source, "-", 1 ) )
Sam Hocevar's avatar
Sam Hocevar committed
379
    {
380 381 382 383 384
        /* stdin */
        p_input->i_handle = 0;
        
        vlc_mutex_lock( &p_input->stream.stream_lock );
        p_input->stream.b_pace_control = 1;
385 386
        p_input->stream.b_seekable = 0;
        p_input->stream.i_size = 0;
387 388
        p_input->stream.i_tell = 0;
        vlc_mutex_unlock( &p_input->stream.stream_lock );
Benoit Steiner's avatar
 
Benoit Steiner committed
389 390 391
    }
    else
    {
392 393 394 395 396 397 398
        if( stat( p_config->p_source, &stat_info ) == (-1) )
        {
            intf_ErrMsg("Cannot stat() file %s (%s)", p_config->p_source,
                        strerror(errno));
            p_input->b_error = 1;
            return;
        }
Michel Kaempf's avatar
Michel Kaempf committed
399

400
        vlc_mutex_lock( &p_input->stream.stream_lock );
Michel Kaempf's avatar
Michel Kaempf committed
401

402 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 428 429 430 431 432 433 434
        /* If we are here we can control the pace... */
        p_input->stream.b_pace_control = 1;

        if( S_ISREG(stat_info.st_mode) || S_ISCHR(stat_info.st_mode)
             || S_ISBLK(stat_info.st_mode) )
        {
            p_input->stream.b_seekable = 1;
            p_input->stream.i_size = stat_info.st_size;
        }
        else if( S_ISFIFO(stat_info.st_mode) || S_ISSOCK(stat_info.st_mode) )
        {
            p_input->stream.b_seekable = 0;
            p_input->stream.i_size = 0;
        }
        else
        {
            vlc_mutex_unlock( &p_input->stream.stream_lock );
            intf_ErrMsg("Unknown file type");
            p_input->b_error = 1;
            return;
        }

        p_input->stream.i_tell = 0;
        vlc_mutex_unlock( &p_input->stream.stream_lock );

        intf_Msg( "Opening file %s", p_config->p_source );
        if( (p_input->i_handle = open( p_config->p_source,
                                       /*O_NONBLOCK | O_LARGEFILE*/0 )) == (-1) )
        {
            intf_ErrMsg("Cannot open file (%s)", strerror(errno));
            p_input->b_error = 1;
            return;
        }
Michel Kaempf's avatar
Michel Kaempf committed
435 436
    }

437
#undef p_config
Michel Kaempf's avatar
Michel Kaempf committed
438
}