input.c 20.4 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-2001 VideoLAN
7
 * $Id: input.c,v 1.181 2002/03/01 01:12:28 stef Exp $
8
 *
9
 * Authors: Christophe Massiot <massiot@via.ecp.fr>
Christophe Massiot's avatar
Christophe Massiot committed
10
 *          Alexis Guillard <alexis.guillard@bt.com>
11 12 13 14 15
 *
 * 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.
16
 * 
17 18
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 20
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
21
 *
22 23 24
 * 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.
25
 *****************************************************************************/
Michel Kaempf's avatar
Michel Kaempf committed
26

27
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
28
 * Preamble
29
 *****************************************************************************/
30 31 32 33
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
34

Sam Hocevar's avatar
Sam Hocevar committed
35 36
#include <videolan/vlc.h>

37
#include <string.h>
38 39
#include <errno.h>

40 41
#ifdef HAVE_SYS_TIMES_H
#   include <sys/times.h>
42
#endif
43

44
#include "netutils.h"
45

46
#include "intf_playlist.h"
47

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

53 54
#include "interface.h"

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

65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85
/*****************************************************************************
 * input_InitBank: initialize the input bank.
 *****************************************************************************/
void input_InitBank ( void )
{
    p_input_bank->i_count = 0;

    /* XXX: Workaround for old interface modules */
    p_input_bank->pp_input[0] = NULL;

    vlc_mutex_init( &p_input_bank->lock );
}

/*****************************************************************************
 * input_EndBank: empty the input bank.
 *****************************************************************************
 * This function ends all unused inputs and empties the bank in
 * case of success.
 *****************************************************************************/
void input_EndBank ( void )
{
86 87
    int i_input;

88
    /* Ask all remaining video outputs to die */
89
    for( i_input = 0; i_input < p_input_bank->i_count; i_input++ )
90
    {
91 92
        input_StopThread(
                p_input_bank->pp_input[ i_input ], NULL );
93
        input_DestroyThread(
94
                p_input_bank->pp_input[ i_input ] );
95 96 97 98 99
    }

    vlc_mutex_destroy( &p_input_bank->lock );
}

100
/*****************************************************************************
101
 * input_CreateThread: creates a new input thread
102
 *****************************************************************************
103 104 105 106
 * 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.
107
 *****************************************************************************/
108
input_thread_t *input_CreateThread ( playlist_item_t *p_item, int *pi_status )
Michel Kaempf's avatar
Michel Kaempf committed
109
{
110 111
    input_thread_t *    p_input;                        /* thread descriptor */

112 113 114
    /* Allocate descriptor */
    p_input = (input_thread_t *)malloc( sizeof(input_thread_t) );
    if( p_input == NULL )
Michel Kaempf's avatar
Michel Kaempf committed
115
    {
116 117
        intf_ErrMsg( "input error: can't allocate input thread (%s)",
                     strerror(errno) );
Michel Kaempf's avatar
Michel Kaempf committed
118 119
        return( NULL );
    }
120 121

    /* Initialize thread properties */
122 123 124
    p_input->b_die      = 0;
    p_input->b_error    = 0;
    p_input->b_eof      = 0;
125 126

    /* Set target */
Christophe Massiot's avatar
Christophe Massiot committed
127
    p_input->psz_source = strdup( p_item->psz_name );
128

129 130
    /* Set status */
    p_input->i_status   = THREAD_CREATE;
131 132 133 134 135 136 137 138 139 140 141 142 143 144

    /* Demux */
    p_input->pf_init    = NULL;
    p_input->pf_end     = NULL;
    p_input->pf_demux   = NULL;
    p_input->pf_rewind  = NULL;

    /* Access */
    p_input->pf_open        = NULL;
    p_input->pf_close       = NULL;
    p_input->pf_read        = NULL;
    p_input->pf_seek        = NULL;
    p_input->pf_set_area    = NULL;
    p_input->pf_set_program = NULL;
145 146 147 148 149 150 151 152 153 154
    
    /* Initialize statistics */
    p_input->c_loops                    = 0;
    p_input->stream.c_packets_read      = 0;
    p_input->stream.c_packets_trashed   = 0;

    /* Set locks. */
    vlc_mutex_init( &p_input->stream.stream_lock );
    vlc_cond_init( &p_input->stream.stream_wait );
    vlc_mutex_init( &p_input->stream.control.control_lock );
Michel Kaempf's avatar
Michel Kaempf committed
155

156
    /* Initialize stream description */
157
    p_input->stream.b_changed = 0;
158 159
    p_input->stream.i_es_number = 0;
    p_input->stream.i_selected_es_number = 0;
160
    p_input->stream.i_pgrm_number = 0;
161
    p_input->stream.i_new_status = p_input->stream.i_new_rate = 0;
162
    p_input->stream.b_new_mute = MUTE_NO_CHANGE;
Christophe Massiot's avatar
Christophe Massiot committed
163
    p_input->stream.i_mux_rate = 0;
Michel Kaempf's avatar
Michel Kaempf committed
164

165 166 167
    /* no stream, no program, no area, no es */
    p_input->stream.p_new_program = NULL;

168 169
    p_input->stream.i_area_nb = 0;
    p_input->stream.pp_areas = NULL;
170
    p_input->stream.p_selected_area = NULL;
171
    p_input->stream.p_new_area = NULL;
172

173 174 175 176
    p_input->stream.pp_selected_es = NULL;
    p_input->stream.p_removed_es = NULL;
    p_input->stream.p_newly_selected_es = NULL;

177
    /* By default there is one area in a stream */
178
    input_AddArea( p_input );
179
    p_input->stream.p_selected_area = p_input->stream.pp_areas[0];
180

181 182 183 184
    /* 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;
185 186 187
    p_input->stream.control.b_grayscale = config_GetIntVariable(
			                      VOUT_GRAYSCALE_VAR );
    p_input->stream.control.i_smp = config_GetIntVariable( VDEC_SMP_VAR );
Michel Kaempf's avatar
Michel Kaempf committed
188

Christophe Massiot's avatar
Christophe Massiot committed
189
    intf_WarnMsg( 1, "input: playlist item `%s'", p_input->psz_source );
190

191
    /* Create thread. */
192 193
    if( vlc_thread_create( &p_input->thread_id, "input",
                           (vlc_thread_func_t)RunThread, (void *) p_input ) )
Michel Kaempf's avatar
Michel Kaempf committed
194
    {
195 196
        intf_ErrMsg( "input error: can't create input thread (%s)",
                     strerror(errno) );
Michel Kaempf's avatar
Michel Kaempf committed
197 198 199
        free( p_input );
        return( NULL );
    }
200

201
#if 0
202 203 204 205
    /* If status is NULL, wait until the thread is created */
    if( pi_status == NULL )
    {
        do
206
        {
207
            msleep( THREAD_SLEEP );
208
        } while( (i_status != THREAD_READY) && (i_status != THREAD_ERROR)
209
                && (i_status != THREAD_FATAL) );
210
    }
211 212
#endif

Michel Kaempf's avatar
Michel Kaempf committed
213 214 215
    return( p_input );
}

216
/*****************************************************************************
217
 * input_StopThread: mark an input thread as zombie
218
 *****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
219
 * This function should not return until the thread is effectively cancelled.
220
 *****************************************************************************/
221
void input_StopThread( input_thread_t *p_input, int *pi_status )
Michel Kaempf's avatar
Michel Kaempf committed
222
{
223 224
    /* Make the thread exit from a possible vlc_cond_wait() */
    vlc_mutex_lock( &p_input->stream.stream_lock );
225

226 227
    /* Request thread destruction */
    p_input->b_die = 1;
Michel Kaempf's avatar
Michel Kaempf committed
228

229 230 231
    vlc_cond_signal( &p_input->stream.stream_wait );
    vlc_mutex_unlock( &p_input->stream.stream_lock );

232
    /* If status is NULL, wait until thread has been destroyed */
233
#if 0
234 235 236 237 238
    if( pi_status == NULL )
    {
        do
        {
            msleep( THREAD_SLEEP );
239 240
        } while ( (i_status != THREAD_OVER) && (i_status != THREAD_ERROR)
                  && (i_status != THREAD_FATAL) );
241
    }
242 243 244 245 246 247 248 249 250 251 252 253 254 255 256
#endif
}

/*****************************************************************************
 * 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 */
    vlc_thread_join( p_input->thread_id );

    /* Destroy Mutex locks */
    vlc_mutex_destroy( &p_input->stream.control.control_lock );
257
    vlc_cond_destroy( &p_input->stream.stream_wait );
258 259 260 261
    vlc_mutex_destroy( &p_input->stream.stream_lock );
    
    /* Free input structure */
    free( p_input );
Michel Kaempf's avatar
Michel Kaempf committed
262 263
}

264
/*****************************************************************************
265
 * RunThread: main thread loop
266
 *****************************************************************************
267
 * Thread in charge of processing the network packets and demultiplexing.
268
 *****************************************************************************/
269
static int RunThread( input_thread_t *p_input )
Michel Kaempf's avatar
Michel Kaempf committed
270
{
271 272 273
    if( InitThread( p_input ) )
    {
        /* If we failed, wait before we are killed, and exit */
274
        p_input->i_status = THREAD_ERROR;
275 276 277
        p_input->b_error = 1;
        ErrorThread( p_input );
        DestroyThread( p_input );
278
        return 0;
279
    }
Michel Kaempf's avatar
Michel Kaempf committed
280

281 282
    p_input->i_status = THREAD_READY;

283
    /* initialization is complete */
284 285 286 287
    vlc_mutex_lock( &p_input->stream.stream_lock );
    p_input->stream.b_changed = 1;
    vlc_mutex_unlock( &p_input->stream.stream_lock );

288 289
    while( !p_input->b_die && !p_input->b_error && !p_input->b_eof )
    {
Christophe Massiot's avatar
Christophe Massiot committed
290
        int i, i_count;
291

292
        p_input->c_loops++;
293

294
        vlc_mutex_lock( &p_input->stream.stream_lock );
295

296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318
        if( p_input->stream.p_new_program )
        {
            if( p_input->pf_set_program != NULL )
            {

                p_input->pf_set_program( p_input, 
                        p_input->stream.p_new_program );

                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;
                }
            }
            p_input->stream.p_new_program = NULL;
        }
        
319 320
        if( p_input->stream.p_new_area )
        {
321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337
            if( p_input->stream.b_seekable && p_input->pf_set_area != NULL )
            {

                p_input->pf_set_area( p_input, p_input->stream.p_new_area );

                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;
                }
            }
338 339 340
            p_input->stream.p_new_area = NULL;
        }

341
        if( p_input->stream.p_selected_area->i_seek != NO_SEEK )
342
        {
343 344
            if( p_input->stream.b_seekable && p_input->pf_seek != NULL )
            {
Christophe Massiot's avatar
Christophe Massiot committed
345 346 347 348
                off_t i_new_pos = p_input->stream.p_selected_area->i_seek;
                vlc_mutex_unlock( &p_input->stream.stream_lock );
                p_input->pf_seek( p_input, i_new_pos );
                vlc_mutex_lock( &p_input->stream.stream_lock );
349 350 351 352 353 354 355 356 357 358 359 360

                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;
                }
Christophe Massiot's avatar
Christophe Massiot committed
361 362 363

                /* Reinitialize buffer manager. */
                input_AccessReinit( p_input );
364
            }
365
            p_input->stream.p_selected_area->i_seek = NO_SEEK;
366
        }
367

368 369 370 371 372 373 374 375 376 377 378 379
        if( p_input->stream.p_removed_es )
        {
            input_UnselectES( p_input, p_input->stream.p_removed_es );
            p_input->stream.p_removed_es = NULL;
        }

        if( p_input->stream.p_newly_selected_es )
        {
            input_SelectES( p_input, p_input->stream.p_newly_selected_es );
            p_input->stream.p_newly_selected_es = NULL;
        }

380 381 382 383 384 385 386 387 388 389 390 391 392 393
        if( p_input->stream.b_new_mute != MUTE_NO_CHANGE )
        {
            if( p_input->stream.b_new_mute )
            {
                input_EscapeAudioDiscontinuity( p_input );
            }

            vlc_mutex_lock( &p_input->stream.control.control_lock );
            p_input->stream.control.b_mute = p_input->stream.b_new_mute;
            vlc_mutex_unlock( &p_input->stream.control.control_lock );

            p_input->stream.b_new_mute = MUTE_NO_CHANGE;
        }

394
        vlc_mutex_unlock( &p_input->stream.stream_lock );
395

Christophe Massiot's avatar
Christophe Massiot committed
396 397
        /* Read and demultiplex some data. */
        i_count = p_input->pf_demux( p_input );
398

399
        if( i_count == 0 && p_input->stream.b_seekable )
400
        {
401 402 403 404 405 406 407 408
            /* End of file - we do not set b_die because only the
             * interface is allowed to do so. */
            intf_WarnMsg( 3, "input: EOF reached" );
            p_input->b_eof = 1;
        }
        else if( i_count < 0 )
        {
            p_input->b_error = 1;
409 410 411
        }
    }

412
    if( p_input->b_error || p_input->b_eof )
413 414 415
    {
        ErrorThread( p_input );
    }
416

417
    EndThread( p_input );
418 419

    DestroyThread( p_input );
420 421

    return 0;
422 423
}

424
/*****************************************************************************
425
 * InitThread: init the input Thread
426
 *****************************************************************************/
427
static int InitThread( input_thread_t * p_input )
Michel Kaempf's avatar
Michel Kaempf committed
428
{
Christophe Massiot's avatar
Christophe Massiot committed
429 430
    /* Parse source string. Syntax : [[<access>][/<demux>]:][<source>] */
    char * psz_parser = p_input->psz_source;
431

Christophe Massiot's avatar
Christophe Massiot committed
432 433 434 435 436
    /* Skip the plug-in names */
    while( *psz_parser && *psz_parser != ':' )
    {
        psz_parser++;
    }
437

Christophe Massiot's avatar
Christophe Massiot committed
438
    if( !*psz_parser )
439
    {
Christophe Massiot's avatar
Christophe Massiot committed
440 441
        p_input->psz_access = p_input->psz_demux = NULL;
        p_input->psz_name = p_input->psz_source;
Michel Kaempf's avatar
Michel Kaempf committed
442
    }
Christophe Massiot's avatar
Christophe Massiot committed
443 444 445
    else
    {
        *psz_parser++ = '\0';
446

Christophe Massiot's avatar
Christophe Massiot committed
447
        p_input->psz_name = psz_parser;
448

Christophe Massiot's avatar
Christophe Massiot committed
449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485
        /* Come back to parse the access and demux plug-ins */
        psz_parser = p_input->psz_source;
        if( !*psz_parser )
        {
            /* No access */
            p_input->psz_access = NULL;
        }
        else if( *psz_parser == '/' )
        {
            /* No access */
            p_input->psz_access = NULL;
            psz_parser++;
        }
        else
        {
            p_input->psz_access = psz_parser;

            while( *psz_parser && *psz_parser != '/' )
            {
                psz_parser++;
            }

            if( *psz_parser == '/' )
            {
                *psz_parser++ = '\0';
            }
        }

        if( !*psz_parser )
        {
            /* No demux */
            p_input->psz_demux = NULL;
        }
        else
        {
            p_input->psz_demux = psz_parser;
        }
Sam Hocevar's avatar
Sam Hocevar committed
486
    }
Christophe Massiot's avatar
Christophe Massiot committed
487 488 489 490 491 492

    intf_WarnMsg( 2, "input: access=%s demux=%s name=%s",
                  p_input->psz_access, p_input->psz_demux,
                  p_input->psz_name );

    if( input_AccessInit( p_input ) == -1 )
493
    {
Christophe Massiot's avatar
Christophe Massiot committed
494
        return( -1 );
495
    }
Christophe Massiot's avatar
Christophe Massiot committed
496 497 498 499 500 501 502

    /* Find and open appropriate access plug-in. */
    p_input->p_access_module = module_Need( MODULE_CAPABILITY_ACCESS,
                                 p_input->psz_access,
                                 (void *)p_input );

    if( p_input->p_access_module == NULL )
503
    {
Christophe Massiot's avatar
Christophe Massiot committed
504 505 506 507
        intf_ErrMsg( "input error: no suitable access plug-in for `%s/%s:%s'",
                     p_input->psz_access, p_input->psz_demux,
                     p_input->psz_name );
        return( -1 );
508
    }
Christophe Massiot's avatar
Christophe Massiot committed
509 510 511 512 513 514 515 516 517 518 519 520

#define f p_input->p_access_module->p_functions->access.functions.access
    p_input->pf_open          = f.pf_open;
    p_input->pf_close         = f.pf_close;
    p_input->pf_read          = f.pf_read;
    p_input->pf_set_area      = f.pf_set_area;
    p_input->pf_set_program   = f.pf_set_program;
    p_input->pf_seek          = f.pf_seek;
#undef f

    /* Waiting for stream. */
    if( p_input->i_mtu )
Christophe Massiot's avatar
Christophe Massiot committed
521
    {
Christophe Massiot's avatar
Christophe Massiot committed
522
        p_input->i_bufsize = p_input->i_mtu;
Christophe Massiot's avatar
Christophe Massiot committed
523
    }
524 525
    else
    {
Christophe Massiot's avatar
Christophe Massiot committed
526
        p_input->i_bufsize = INPUT_DEFAULT_BUFSIZE;
527
    }
528

Christophe Massiot's avatar
Christophe Massiot committed
529
    if( p_input->p_current_data == NULL )
530
    {
Christophe Massiot's avatar
Christophe Massiot committed
531 532 533 534 535 536 537 538
        while( !input_FillBuffer( p_input ) )
        {
            if( p_input->b_die || p_input->b_error )
            {
                module_Unneed( p_input->p_access_module );
                return( -1 );
            }
        }
539
    }
540

Christophe Massiot's avatar
Christophe Massiot committed
541 542 543 544
    /* Find and open appropriate demux plug-in. */
    p_input->p_demux_module = module_Need( MODULE_CAPABILITY_DEMUX,
                                 p_input->psz_demux,
                                 (void *)p_input );
545

Christophe Massiot's avatar
Christophe Massiot committed
546
    if( p_input->p_demux_module == NULL )
547
    {
Christophe Massiot's avatar
Christophe Massiot committed
548 549 550 551
        intf_ErrMsg( "input error: no suitable demux plug-in for `%s/%s:%s'",
                     p_input->psz_access, p_input->psz_demux,
                     p_input->psz_name );
        module_Unneed( p_input->p_access_module );
552 553 554
        return( -1 );
    }

Christophe Massiot's avatar
Christophe Massiot committed
555 556 557 558 559 560 561
#define f p_input->p_demux_module->p_functions->demux.functions.demux
    p_input->pf_init          = f.pf_init;
    p_input->pf_end           = f.pf_end;
    p_input->pf_demux         = f.pf_demux;
    p_input->pf_rewind        = f.pf_rewind;
#undef f

562
    return( 0 );
Michel Kaempf's avatar
Michel Kaempf committed
563 564
}

565
/*****************************************************************************
566
 * ErrorThread: RunThread() error loop
567
 *****************************************************************************
568
 * This function is called when an error occured during thread main's loop.
569
 *****************************************************************************/
570
static void ErrorThread( input_thread_t *p_input )
Michel Kaempf's avatar
Michel Kaempf committed
571
{
572
    while( !p_input->b_die )
Michel Kaempf's avatar
Michel Kaempf committed
573
    {
574 575
        /* Sleep a while */
        msleep( INPUT_IDLE_SLEEP );
Michel Kaempf's avatar
Michel Kaempf committed
576 577 578
    }
}

579
/*****************************************************************************
580
 * EndThread: end the input thread
581
 *****************************************************************************/
582
static void EndThread( input_thread_t * p_input )
583
{
584
    /* Store status */
585
    p_input->i_status = THREAD_END;
586

587
    if( p_main->b_stats )
588
    {
589
#ifdef HAVE_SYS_TIMES_H
590 591
        /* Display statistics */
        struct tms  cpu_usage;
592 593
        times( &cpu_usage );

594 595 596
        intf_StatMsg( "input stats: %d loops consuming user: %d, system: %d",
                      p_input->c_loops,
                      cpu_usage.tms_utime, cpu_usage.tms_stime );
597 598 599
#else
        intf_StatMsg( "input stats: %d loops", p_input->c_loops );
#endif
600 601

        input_DumpStream( p_input );
602 603 604 605 606 607 608
    }

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

    /* Free demultiplexer's data */
    p_input->pf_end( p_input );
Christophe Massiot's avatar
Christophe Massiot committed
609
    module_Unneed( p_input->p_demux_module );
610

Christophe Massiot's avatar
Christophe Massiot committed
611
    /* Close the access plug-in */
612 613 614 615 616 617 618 619
    CloseThread( p_input );
}

/*****************************************************************************
 * CloseThread: close the target
 *****************************************************************************/
static void CloseThread( input_thread_t * p_input )
{
Christophe Massiot's avatar
Christophe Massiot committed
620 621
    p_input->pf_close( p_input );
    module_Unneed( p_input->p_access_module );
622

Christophe Massiot's avatar
Christophe Massiot committed
623 624 625
    input_AccessEnd( p_input );

    free( p_input->psz_source );
626 627 628 629 630 631 632
}

/*****************************************************************************
 * DestroyThread: destroy the input thread
 *****************************************************************************/
static void DestroyThread( input_thread_t * p_input )
{
633
    /* Update status */
634
    p_input->i_status = THREAD_OVER;
635
}
636