input.c 13.3 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.63 2000/12/21 19:24:26 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
    p_input->stream.i_es_number = 0;
    p_input->stream.i_selected_es_number = 0;
100
    p_input->stream.i_pgrm_number = 0;
Michel Kaempf's avatar
Michel Kaempf committed
101

102 103 104 105 106 107 108
    /* 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
109 110

    /* Create thread and set locks. */
111 112 113 114
    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
115
    {
116
        intf_ErrMsg("error: %s\n", strerror(errno) );
Michel Kaempf's avatar
Michel Kaempf committed
117
        free( p_input );
118
        free( p_config );
Michel Kaempf's avatar
Michel Kaempf committed
119 120
        return( NULL );
    }
121

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

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

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

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

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

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

175
    InitThread( p_input );
Michel Kaempf's avatar
Michel Kaempf committed
176

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

183 184 185
        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 )
186
        {
187 188
            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
189
        }
190
        vlc_mutex_unlock( &p_input->stream.control.control_lock );
191

192 193 194 195
        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++ )
196
        {
197 198
            p_input->p_plugin->pf_demux( p_input, pp_packets[i] );
        }
199

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

212 213 214 215
    if( p_input->b_error )
    {
        ErrorThread( p_input );
    }
216

217 218
    EndThread( p_input );
    intf_DbgMsg("Thread end");
219 220
}

221
/*****************************************************************************
222
 * InitThread: init the input thread
223
 *****************************************************************************/
224 225
input_capabilities_t * PSKludge( void );
static void InitThread( input_thread_t * p_input )
Michel Kaempf's avatar
Michel Kaempf committed
226
{
227 228 229
    /* 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
230 231

#ifdef STATS
232 233 234 235 236 237
    /* 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
238
#endif
239

240 241 242 243 244 245 246 247
    /* 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
248
        {
249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264
            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;
265
#endif
Michel Kaempf's avatar
Michel Kaempf committed
266
    }
267 268 269 270 271 272 273 274

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

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

291
/*****************************************************************************
292
 * EndThread: end the input thread
293
 *****************************************************************************/
294
static void EndThread( input_thread_t * p_input )
295
{
296
    int *       pi_status;                                  /* thread status */
297

298 299 300
    /* Store status */
    pi_status = p_input->pi_status;
    *pi_status = THREAD_END;
301

302 303 304 305 306 307 308 309 310 311
#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

312 313
    /* Free all ES and destroy all decoder threads */
    input_EndStream( p_input );
314

315
    /* Free demultiplexer's data */
316 317 318
    p_input->p_plugin->pf_end( p_input );
    free( p_input->p_plugin );

319
    /* Free input structure */
320
    free( p_input );
321

322 323
    /* Update status */
    *pi_status = THREAD_OVER;
324
}
325

326
/*****************************************************************************
327
 * NetworkOpen : open a network socket descriptor
328
 *****************************************************************************/
329
static void NetworkOpen( input_thread_t * p_input )
330
{
331
    /* straight copy & paste of input_network.c of input-I */
332

333 334 335 336
    /* We cannot rewind nor lseek() */
    p_input->stream.b_seekable = 0;
    /* We cannot control the pace */
    p_input->stream.b_pace_control = 0;
337 338
}

339
/*****************************************************************************
340
 * FileOpen : open a file descriptor
341
 *****************************************************************************/
342
static void FileOpen( input_thread_t * p_input )
Michel Kaempf's avatar
Michel Kaempf committed
343
{
344
    struct stat         stat_info;
Michel Kaempf's avatar
Michel Kaempf committed
345

346
#define p_config    p_input->p_config
Michel Kaempf's avatar
Michel Kaempf committed
347

348
    if( !strncmp( p_config->p_source, "-", 1 ) )
349
    {
350 351 352 353 354
        /* stdin */
        p_input->i_handle = 0;
        
        vlc_mutex_lock( &p_input->stream.stream_lock );
        p_input->stream.b_pace_control = 1;
355 356
        p_input->stream.b_seekable = 0;
        p_input->stream.i_size = 0;
357 358
        p_input->stream.i_tell = 0;
        vlc_mutex_unlock( &p_input->stream.stream_lock );
Benoit Steiner's avatar
 
Benoit Steiner committed
359 360 361
    }
    else
    {
362 363 364 365 366 367 368
        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
369

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

372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404
        /* 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
405 406
    }

407
#undef p_config
Michel Kaempf's avatar
Michel Kaempf committed
408
}