input.c 14 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.80 2001/02/12 13:20:14 massiot Exp $
8
 *
9
 * Authors: Christophe Massiot <massiot@via.ecp.fr>
10 11 12 13 14
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
15
 * 
16 17
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 19
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
20
 *
21 22 23
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
24
 *****************************************************************************/
Michel Kaempf's avatar
Michel Kaempf committed
25

26
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
27
 * Preamble
28
 *****************************************************************************/
29 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"
Sam Hocevar's avatar
 
Sam Hocevar committed
47
#include "modules.h"
48

49
#include "intf_msg.h"
Sam Hocevar's avatar
 
Sam Hocevar committed
50
#include "intf_plst.h"
51

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

56
#include "input.h"
Sam Hocevar's avatar
 
Sam Hocevar committed
57 58 59
#include "interface.h"

#include "main.h"
Michel Kaempf's avatar
Michel Kaempf committed
60

61
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
62
 * Local prototypes
63
 *****************************************************************************/
64
static void RunThread   ( input_thread_t *p_input );
Sam Hocevar's avatar
 
Sam Hocevar committed
65
static void InitThread  ( input_thread_t *p_input );
66 67
static void ErrorThread ( input_thread_t *p_input );
static void EndThread   ( input_thread_t *p_input );
Michel Kaempf's avatar
Michel Kaempf committed
68

69
/*****************************************************************************
70
 * input_CreateThread: creates a new input thread
71
 *****************************************************************************
72 73 74 75
 * 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.
76
 *****************************************************************************/
Sam Hocevar's avatar
 
Sam Hocevar committed
77
input_thread_t *input_CreateThread ( playlist_item_t *p_item, int *pi_status )
Michel Kaempf's avatar
Michel Kaempf committed
78
{
79 80 81
    input_thread_t *    p_input;                        /* thread descriptor */
    int                 i_status;                           /* thread status */

82 83 84
    /* Allocate descriptor */
    p_input = (input_thread_t *)malloc( sizeof(input_thread_t) );
    if( p_input == NULL )
Michel Kaempf's avatar
Michel Kaempf committed
85
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
86 87
        intf_ErrMsg( "input error: can't allocate input thread (%s)",
                     strerror(errno) );
Michel Kaempf's avatar
Michel Kaempf committed
88 89
        return( NULL );
    }
90 91 92 93

    /* Initialize thread properties */
    p_input->b_die              = 0;
    p_input->b_error            = 0;
Sam Hocevar's avatar
 
Sam Hocevar committed
94 95 96 97 98
    p_input->b_eof              = 0;

    /* Set target */
    p_input->p_source           = p_item->psz_name;

99
    /* I have never understood that stuff --Meuuh */
100 101
    p_input->pi_status          = (pi_status != NULL) ? pi_status : &i_status;
    *p_input->pi_status         = THREAD_CREATE;
Michel Kaempf's avatar
Michel Kaempf committed
102

103
    /* Initialize stream description */
104 105
    p_input->stream.i_es_number = 0;
    p_input->stream.i_selected_es_number = 0;
106
    p_input->stream.i_pgrm_number = 0;
107
    p_input->stream.i_new_status = p_input->stream.i_new_rate = 0;
108
    p_input->stream.i_seek = NO_SEEK;
Michel Kaempf's avatar
Michel Kaempf committed
109

110 111 112 113 114
    /* Initialize stream control properties. */
    p_input->stream.control.i_status = PLAYING_S;
    p_input->stream.control.i_rate = DEFAULT_RATE;
    p_input->stream.control.b_mute = 0;
    p_input->stream.control.b_bw = 0;
Michel Kaempf's avatar
Michel Kaempf committed
115

Sam Hocevar's avatar
 
Sam Hocevar committed
116 117
    /* Initialize default settings for spawned decoders */
    p_input->p_default_aout = p_main->p_aout;
Sam Hocevar's avatar
 
Sam Hocevar committed
118
    p_input->p_default_vout = p_main->p_vout;
Sam Hocevar's avatar
 
Sam Hocevar committed
119

Michel Kaempf's avatar
Michel Kaempf committed
120
    /* Create thread and set locks. */
121
    vlc_mutex_init( &p_input->stream.stream_lock );
122
    vlc_cond_init( &p_input->stream.stream_wait );
123 124 125
    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
126
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
127 128
        intf_ErrMsg( "input error: can't create input thread (%s)",
                     strerror(errno) );
Michel Kaempf's avatar
Michel Kaempf committed
129 130 131
        free( p_input );
        return( NULL );
    }
132

133 134 135 136
    /* If status is NULL, wait until the thread is created */
    if( pi_status == NULL )
    {
        do
137
        {
138
            msleep( THREAD_SLEEP );
139
        } while( (i_status != THREAD_READY) && (i_status != THREAD_ERROR)
Sam Hocevar's avatar
 
Sam Hocevar committed
140
                && (i_status != THREAD_FATAL) );
141 142
        if( i_status != THREAD_READY )
        {
143 144
            return( NULL );
        }
145
    }
Michel Kaempf's avatar
Michel Kaempf committed
146 147 148
    return( p_input );
}

149
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
150
 * input_DestroyThread: mark an input thread as zombie
151
 *****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
152
 * This function should not return until the thread is effectively cancelled.
153
 *****************************************************************************/
154
void input_DestroyThread( input_thread_t *p_input, int *pi_status )
Michel Kaempf's avatar
Michel Kaempf committed
155
{
156
    int         i_status;                                   /* thread status */
157 158 159

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

162 163
    /* Request thread destruction */
    p_input->b_die = 1;
Michel Kaempf's avatar
Michel Kaempf committed
164

165 166 167 168 169
    /* Make the thread exit of an eventual vlc_cond_wait() */
    vlc_mutex_lock( &p_input->stream.stream_lock );
    vlc_cond_signal( &p_input->stream.stream_wait );
    vlc_mutex_unlock( &p_input->stream.stream_lock );

170 171 172 173 174 175
    /* If status is NULL, wait until thread has been destroyed */
    if( pi_status == NULL )
    {
        do
        {
            msleep( THREAD_SLEEP );
176 177
        } while ( (i_status != THREAD_OVER) && (i_status != THREAD_ERROR)
                  && (i_status != THREAD_FATAL) );
178
    }
Michel Kaempf's avatar
Michel Kaempf committed
179 180
}

181
/*****************************************************************************
182
 * RunThread: main thread loop
183
 *****************************************************************************
184
 * Thread in charge of processing the network packets and demultiplexing.
185
 *****************************************************************************/
186
static void RunThread( input_thread_t *p_input )
Michel Kaempf's avatar
Michel Kaempf committed
187
{
188 189
    data_packet_t *         pp_packets[INPUT_READ_ONCE];
    int                     i_error, i;
Michel Kaempf's avatar
Michel Kaempf committed
190

Sam Hocevar's avatar
 
Sam Hocevar committed
191
    InitThread( p_input );
Michel Kaempf's avatar
Michel Kaempf committed
192

Sam Hocevar's avatar
 
Sam Hocevar committed
193
    while( !p_input->b_die && !p_input->b_error && !p_input->b_eof )
194 195
    {

Sam Hocevar's avatar
 
Sam Hocevar committed
196
#ifdef STATS
Sam Hocevar's avatar
 
Sam Hocevar committed
197
        p_input->c_loops++;
Sam Hocevar's avatar
 
Sam Hocevar committed
198 199
#endif

200
        vlc_mutex_lock( &p_input->stream.stream_lock );
201
        if( p_input->stream.i_seek != NO_SEEK )
Sam Hocevar's avatar
 
Sam Hocevar committed
202
        {
203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218
            if( p_input->stream.b_seekable && p_input->pf_seek != NULL )
            {
                p_input->pf_seek( p_input, p_input->stream.i_seek );

                for( i = 0; i < p_input->stream.i_pgrm_number; i++ )
                {
                    pgrm_descriptor_t * p_pgrm
                                            = p_input->stream.pp_programs[i];
                    /* Escape all decoders for the stream discontinuity they
                     * will encounter. */
                    input_EscapeDiscontinuity( p_input, p_pgrm );

                    /* Reinitialize synchro. */
                    p_pgrm->i_synchro_state = SYNCHRO_REINIT;
                }
            }
219
            p_input->stream.i_seek = NO_SEEK;
Sam Hocevar's avatar
 
Sam Hocevar committed
220
        }
221
        vlc_mutex_unlock( &p_input->stream.stream_lock );
Sam Hocevar's avatar
 
Sam Hocevar committed
222 223

        i_error = p_input->pf_read( p_input, pp_packets );
Sam Hocevar's avatar
 
Sam Hocevar committed
224

Sam Hocevar's avatar
 
Sam Hocevar committed
225 226 227 228 229
        /* Demultiplex read packets. */
        for( i = 0; i < INPUT_READ_ONCE && pp_packets[i] != NULL; i++ )
        {
            p_input->pf_demux( p_input, pp_packets[i] );
        }
Sam Hocevar's avatar
 
Sam Hocevar committed
230

Sam Hocevar's avatar
 
Sam Hocevar committed
231 232 233
        if( i_error )
        {
            if( i_error == 1 )
Sam Hocevar's avatar
Sam Hocevar committed
234
            {
Sam Hocevar's avatar
 
Sam Hocevar committed
235 236 237 238
                /* End of file - we do not set b_die because only the
                 * interface is allowed to do so. */
                intf_WarnMsg( 1, "End of file reached" );
                p_input->b_eof = 1;
Sam Hocevar's avatar
 
Sam Hocevar committed
239
            }
Sam Hocevar's avatar
 
Sam Hocevar committed
240
            else
Sam Hocevar's avatar
 
Sam Hocevar committed
241
            {
Sam Hocevar's avatar
 
Sam Hocevar committed
242
                p_input->b_error = 1;
Sam Hocevar's avatar
Sam Hocevar committed
243
            }
244 245 246
        }
    }

Sam Hocevar's avatar
 
Sam Hocevar committed
247
    if( p_input->b_error || p_input->b_eof )
248 249 250
    {
        ErrorThread( p_input );
    }
251

252 253
    EndThread( p_input );
    intf_DbgMsg("Thread end");
254 255
}

256
/*****************************************************************************
Sam Hocevar's avatar
 
Sam Hocevar committed
257
 * InitThread: init the input Thread
258
 *****************************************************************************/
Sam Hocevar's avatar
 
Sam Hocevar committed
259
static void InitThread( input_thread_t * p_input )
Michel Kaempf's avatar
Michel Kaempf committed
260 261 262
{

#ifdef STATS
263 264 265 266 267 268
    /* 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
269
#endif
Sam Hocevar's avatar
Sam Hocevar committed
270

Sam Hocevar's avatar
 
Sam Hocevar committed
271
    p_input->p_input_module = module_Need( p_main->p_bank,
Sam Hocevar's avatar
 
Sam Hocevar committed
272 273 274
                                           MODULE_CAPABILITY_INPUT, NULL );

    if( p_input->p_input_module == NULL )
275
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
276
        intf_ErrMsg( "input error: no suitable input module" );
277
        p_input->b_error = 1;
Sam Hocevar's avatar
 
Sam Hocevar committed
278
        return;
Michel Kaempf's avatar
Michel Kaempf committed
279
    }
280

Sam Hocevar's avatar
 
Sam Hocevar committed
281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296
#define f p_input->p_input_module->p_functions->input.functions.input
    p_input->pf_init          = f.pf_init;
    p_input->pf_open          = f.pf_open;
    p_input->pf_close         = f.pf_close;
    p_input->pf_end           = f.pf_end;
    p_input->pf_read          = f.pf_read;
    p_input->pf_demux         = f.pf_demux;
    p_input->pf_new_packet    = f.pf_new_packet;
    p_input->pf_new_pes       = f.pf_new_pes;
    p_input->pf_delete_packet = f.pf_delete_packet;
    p_input->pf_delete_pes    = f.pf_delete_pes;
    p_input->pf_rewind        = f.pf_rewind;
    p_input->pf_seek          = f.pf_seek;
#undef f

    p_input->pf_open( p_input );
297

Sam Hocevar's avatar
 
Sam Hocevar committed
298
    if( p_input->b_error )
299
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
300
        module_Unneed( p_main->p_bank, p_input->p_input_module );
301
    }
Sam Hocevar's avatar
 
Sam Hocevar committed
302
    else
Sam Hocevar's avatar
 
Sam Hocevar committed
303
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
304
        p_input->pf_init( p_input );
Sam Hocevar's avatar
 
Sam Hocevar committed
305 306
    }

Sam Hocevar's avatar
 
Sam Hocevar committed
307
    *p_input->pi_status = THREAD_READY;
Michel Kaempf's avatar
Michel Kaempf committed
308 309
}

310
/*****************************************************************************
311
 * ErrorThread: RunThread() error loop
312
 *****************************************************************************
313
 * This function is called when an error occured during thread main's loop.
314
 *****************************************************************************/
315
static void ErrorThread( input_thread_t *p_input )
Michel Kaempf's avatar
Michel Kaempf committed
316
{
317
    while( !p_input->b_die )
Michel Kaempf's avatar
Michel Kaempf committed
318
    {
319 320
        /* Sleep a while */
        msleep( INPUT_IDLE_SLEEP );
Michel Kaempf's avatar
Michel Kaempf committed
321 322 323
    }
}

324
/*****************************************************************************
325
 * EndThread: end the input thread
326
 *****************************************************************************/
327
static void EndThread( input_thread_t * p_input )
328
{
329
    int *       pi_status;                                  /* thread status */
330

331 332 333
    /* Store status */
    pi_status = p_input->pi_status;
    *pi_status = THREAD_END;
Sam Hocevar's avatar
Sam Hocevar committed
334

Sam Hocevar's avatar
 
Sam Hocevar committed
335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354
#ifdef STATS
    {
        struct tms cpu_usage;
        times( &cpu_usage );

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

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

    /* Close stream */
    p_input->pf_close( p_input );

    /* Free demultiplexer's data */
    p_input->pf_end( p_input );

    /* Release modules */
Sam Hocevar's avatar
 
Sam Hocevar committed
355
    module_Unneed( p_main->p_bank, p_input->p_input_module );
Sam Hocevar's avatar
 
Sam Hocevar committed
356

Henri Fallon's avatar
 
Henri Fallon committed
357 358
    /* Destroy Mutex locks */
    vlc_mutex_destroy( &p_input->stream.control.control_lock );
Henri Fallon's avatar
 
Henri Fallon committed
359
    vlc_mutex_destroy( &p_input->stream.stream_lock );
Henri Fallon's avatar
 
Henri Fallon committed
360
    
361
    /* Free input structure */
362
    free( p_input );
363

364 365
    /* Update status */
    *pi_status = THREAD_OVER;
Sam Hocevar's avatar
Sam Hocevar committed
366
}
367

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

Sam Hocevar's avatar
 
Sam Hocevar committed
375
    if( stat( p_input->p_source, &stat_info ) == (-1) )
Sam Hocevar's avatar
 
Sam Hocevar committed
376
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
377
        intf_ErrMsg( "input error: cannot stat() file `%s' (%s)",
Sam Hocevar's avatar
 
Sam Hocevar committed
378
                     p_input->p_source, strerror(errno));
Sam Hocevar's avatar
 
Sam Hocevar committed
379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394
        p_input->b_error = 1;
        return;
    }

    vlc_mutex_lock( &p_input->stream.stream_lock );

    /* 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) )
Sam Hocevar's avatar
Sam Hocevar committed
395
    {
396 397
        p_input->stream.b_seekable = 0;
        p_input->stream.i_size = 0;
Benoit Steiner's avatar
 
Benoit Steiner committed
398 399 400
    }
    else
    {
401
        vlc_mutex_unlock( &p_input->stream.stream_lock );
Sam Hocevar's avatar
 
Sam Hocevar committed
402
        intf_ErrMsg( "input error: unknown file type for `%s'",
Sam Hocevar's avatar
 
Sam Hocevar committed
403
                     p_input->p_source );
Sam Hocevar's avatar
 
Sam Hocevar committed
404 405 406
        p_input->b_error = 1;
        return;
    }
407

Sam Hocevar's avatar
 
Sam Hocevar committed
408 409 410
    p_input->stream.i_tell = 0;
    vlc_mutex_unlock( &p_input->stream.stream_lock );

Sam Hocevar's avatar
 
Sam Hocevar committed
411 412
    intf_Msg( "input: opening file %s", p_input->p_source );
    if( (p_input->i_handle = open( p_input->p_source,
Sam Hocevar's avatar
 
Sam Hocevar committed
413 414
                                   /*O_NONBLOCK | O_LARGEFILE*/0 )) == (-1) )
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
415
        intf_ErrMsg( "input error: cannot open file (%s)", strerror(errno) );
Sam Hocevar's avatar
 
Sam Hocevar committed
416 417
        p_input->b_error = 1;
        return;
Michel Kaempf's avatar
Michel Kaempf committed
418 419 420
    }

}
Stéphane Borel's avatar
Stéphane Borel committed
421 422

/*****************************************************************************
Sam Hocevar's avatar
 
Sam Hocevar committed
423
 * input_FileClose : close a file descriptor
Stéphane Borel's avatar
Stéphane Borel committed
424
 *****************************************************************************/
Sam Hocevar's avatar
 
Sam Hocevar committed
425
void input_FileClose( input_thread_t * p_input )
Stéphane Borel's avatar
Stéphane Borel committed
426
{
Sam Hocevar's avatar
 
Sam Hocevar committed
427
    close( p_input->i_handle );
Stéphane Borel's avatar
Stéphane Borel committed
428

Sam Hocevar's avatar
 
Sam Hocevar committed
429
    return;
Stéphane Borel's avatar
Stéphane Borel committed
430
}
Sam Hocevar's avatar
 
Sam Hocevar committed
431