video_parser.c 15.8 KB
Newer Older
1
/*****************************************************************************
Stéphane Borel's avatar
Stéphane Borel committed
2
 * video_parser.c : video parser thread
3 4 5
 *****************************************************************************
 * Copyright (C) 1999, 2000 VideoLAN
 *
6 7
 * Authors: Christophe Massiot <massiot@via.ecp.fr>
 *          Samuel Hocevar <sam@via.ecp.fr>
8 9 10 11 12
 *
 * 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.
13
 * 
14 15
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 17
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
18
 *
19 20 21
 * 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.
22
 *****************************************************************************/
23

24
/* FIXME: passer en terminate/destroy avec les signaux supplmentaires ?? */
25

26
/*****************************************************************************
27
 * Preamble
28
 *****************************************************************************/
29 30
#include "defs.h"

31 32 33 34
#include <stdlib.h>                                      /* malloc(), free() */
#include <unistd.h>                                              /* getpid() */
#include <sys/types.h>                        /* on BSD, uio.h needs types.h */
#include <sys/uio.h>                                            /* "input.h" */
35 36
#include <errno.h>
#include <string.h>
37 38 39

#include "config.h"
#include "common.h"
40
#include "threads.h"
41
#include "mtime.h"
42
#include "plugins.h"
43 44

#include "intf_msg.h"
45
#include "debug.h"                 /* XXX?? temporaire, requis par netlist.h */
46 47 48 49 50 51

#include "input.h"
#include "input_netlist.h"
#include "decoder_fifo.h"
#include "video.h"
#include "video_output.h"
52 53

#include "vdec_idct.h"
54
#include "video_decoder.h"
55 56 57 58
#include "vdec_motion.h"

#include "vpar_blocks.h"
#include "vpar_headers.h"
59
#include "vpar_synchro.h"
Stéphane Borel's avatar
Stéphane Borel committed
60
#include "video_parser.h"
61
#include "video_fifo.h"
62 63 64 65 66

/*
 * Local prototypes
 */
//static int      CheckConfiguration  ( video_cfg_t *p_cfg );
Stéphane Borel's avatar
Stéphane Borel committed
67 68 69 70
static int      InitThread          ( vpar_thread_t *p_vpar );
static void     RunThread           ( vpar_thread_t *p_vpar );
static void     ErrorThread         ( vpar_thread_t *p_vpar );
static void     EndThread           ( vpar_thread_t *p_vpar );
71

72
/*****************************************************************************
Stéphane Borel's avatar
Stéphane Borel committed
73
 * vpar_CreateThread: create a generic parser thread
74
 *****************************************************************************
Stéphane Borel's avatar
Stéphane Borel committed
75
 * This function creates a new video parser thread, and returns a pointer
76 77
 * to its description. On error, it returns NULL.
 * Following configuration properties are used:
78
 * XXX??
79
 *****************************************************************************/
Jean-Marc Dressler's avatar
 
Jean-Marc Dressler committed
80 81
#include "main.h"
#include "interface.h"
82 83
extern main_t *     p_main;

Stéphane Borel's avatar
Stéphane Borel committed
84
vpar_thread_t * vpar_CreateThread( /* video_cfg_t *p_cfg, */ input_thread_t *p_input /*,
85 86
                                   vout_thread_t *p_vout, int *pi_status */ )
{
Stéphane Borel's avatar
Stéphane Borel committed
87
    vpar_thread_t *     p_vpar;
88

89
    intf_DbgMsg( "vpar debug: creating video parser thread\n" );
90 91

    /* Allocate the memory needed to store the thread's structure */
Stéphane Borel's avatar
Stéphane Borel committed
92
    if ( (p_vpar = (vpar_thread_t *)malloc( sizeof(vpar_thread_t) )) == NULL )
93
    {
94 95
        intf_ErrMsg( "vpar error: not enough memory "
                     "for vpar_CreateThread() to create the new thread\n");
96 97 98 99 100 101
        return( NULL );
    }

    /*
     * Initialize the thread properties
     */
Stéphane Borel's avatar
Stéphane Borel committed
102 103
    p_vpar->b_die = 0;
    p_vpar->b_error = 0;
104 105 106 107

    /*
     * Initialize the input properties
     */
108 109
    /* Initialize the decoder fifo's data lock and conditional variable
     * and set its buffer as empty */
Stéphane Borel's avatar
Stéphane Borel committed
110 111 112 113
    vlc_mutex_init( &p_vpar->fifo.data_lock );
    vlc_cond_init( &p_vpar->fifo.data_wait );
    p_vpar->fifo.i_start = 0;
    p_vpar->fifo.i_end = 0;
114
    /* Initialize the bit stream structure */
Stéphane Borel's avatar
Stéphane Borel committed
115
    p_vpar->bit_stream.p_input = p_input;
116
    p_vpar->bit_stream.p_decoder_fifo = &p_vpar->fifo;
Stéphane Borel's avatar
Stéphane Borel committed
117 118
    p_vpar->bit_stream.fifo.buffer = 0;
    p_vpar->bit_stream.fifo.i_available = 0;
119

120 121
    /* FIXME !!!!?? */
    p_vpar->p_vout = p_main->p_intf->p_vout;
Jean-Marc Dressler's avatar
 
Jean-Marc Dressler committed
122

Stéphane Borel's avatar
Stéphane Borel committed
123
    /* Spawn the video parser thread */
124 125
    if ( vlc_thread_create( &p_vpar->thread_id, "video parser",
                            (vlc_thread_func_t)RunThread, (void *)p_vpar ) )
126
    {
Stéphane Borel's avatar
Stéphane Borel committed
127 128
        intf_ErrMsg("vpar error: can't spawn video parser thread\n");
        free( p_vpar );
129 130 131
        return( NULL );
    }

Stéphane Borel's avatar
Stéphane Borel committed
132 133
    intf_DbgMsg("vpar debug: video parser thread (%p) created\n", p_vpar);
    return( p_vpar );
134 135
}

136
/*****************************************************************************
Stéphane Borel's avatar
Stéphane Borel committed
137
 * vpar_DestroyThread: destroy a generic parser thread
138
 *****************************************************************************
139 140 141
 * Destroy a terminated thread. This function will return 0 if the thread could
 * be destroyed, and non 0 else. The last case probably means that the thread
 * was still active, and another try may succeed.
142
 *****************************************************************************/
143
void vpar_DestroyThread( vpar_thread_t *p_vpar /*, int *pi_status */ )
144
{
145 146
    intf_DbgMsg( "vpar debug: requesting termination of "
                 "video parser thread %p\n", p_vpar);
147 148

    /* Ask thread to kill itself */
Stéphane Borel's avatar
Stéphane Borel committed
149 150 151 152 153
    p_vpar->b_die = 1;
    /* Make sure the parser thread leaves the GetByte() function */
    vlc_mutex_lock( &(p_vpar->fifo.data_lock) );
    vlc_cond_signal( &(p_vpar->fifo.data_wait) );
    vlc_mutex_unlock( &(p_vpar->fifo.data_lock) );
154

Stéphane Borel's avatar
Stéphane Borel committed
155
    /* Waiting for the parser thread to exit */
156
    /* Remove this as soon as the "status" flag is implemented */
Stéphane Borel's avatar
Stéphane Borel committed
157
    vlc_thread_join( p_vpar->thread_id );
158 159 160 161
}

/* following functions are local */

162
/*****************************************************************************
Stéphane Borel's avatar
Stéphane Borel committed
163
 * CheckConfiguration: check vpar_CreateThread() configuration
164
 *****************************************************************************
165 166
 * Set default parameters where required. In DEBUG mode, check if configuration
 * is valid.
167
 *****************************************************************************/
168 169 170
#if 0
static int CheckConfiguration( video_cfg_t *p_cfg )
{
171
    /* XXX?? */
172 173 174 175 176

    return( 0 );
}
#endif

177
/*****************************************************************************
Stéphane Borel's avatar
Stéphane Borel committed
178
 * InitThread: initialize vpar output thread
179
 *****************************************************************************
180 181 182
 * This function is called from RunThread and performs the second step of the
 * initialization. It returns 0 on success. Note that the thread's flag are not
 * modified inside this function.
183
 *****************************************************************************/
Stéphane Borel's avatar
Stéphane Borel committed
184
static int InitThread( vpar_thread_t *p_vpar )
185
{
Michel Kaempf's avatar
Michel Kaempf committed
186 187 188 189
#ifdef VDEC_SMP
    int i_dummy;
#endif

Stéphane Borel's avatar
Stéphane Borel committed
190
    intf_DbgMsg("vpar debug: initializing video parser thread %p\n", p_vpar);
191 192 193

    /* Our first job is to initialize the bit stream structure with the
     * beginning of the input stream */
Stéphane Borel's avatar
Stéphane Borel committed
194
    vlc_mutex_lock( &p_vpar->fifo.data_lock );
195
    while ( DECODER_FIFO_ISEMPTY(p_vpar->fifo) )
196
    {
Michel Kaempf's avatar
Michel Kaempf committed
197 198 199 200 201
        if ( p_vpar->b_die )
        {
            vlc_mutex_unlock( &p_vpar->fifo.data_lock );
            return( 1 );
        }
Stéphane Borel's avatar
Stéphane Borel committed
202
        vlc_cond_wait( &p_vpar->fifo.data_wait, &p_vpar->fifo.data_lock );
203
    }
204
    p_vpar->bit_stream.p_ts = DECODER_FIFO_START( p_vpar->fifo )->p_first_ts;
205 206 207 208
    p_vpar->bit_stream.p_byte = p_vpar->bit_stream.p_ts->buffer
                                + p_vpar->bit_stream.p_ts->i_payload_start;
    p_vpar->bit_stream.p_end = p_vpar->bit_stream.p_ts->buffer
                               + p_vpar->bit_stream.p_ts->i_payload_end;
Stéphane Borel's avatar
Stéphane Borel committed
209
    vlc_mutex_unlock( &p_vpar->fifo.data_lock );
210

211
    /* Initialize parsing data */
212 213 214 215 216 217
    p_vpar->sequence.p_forward = NULL;
    p_vpar->sequence.p_backward = NULL;
    p_vpar->sequence.intra_quant.b_allocated = 0;
    p_vpar->sequence.nonintra_quant.b_allocated = 0;
    p_vpar->sequence.chroma_intra_quant.b_allocated = 0;
    p_vpar->sequence.chroma_nonintra_quant.b_allocated = 0;
218

Stéphane Borel's avatar
 
Stéphane Borel committed
219 220 221 222 223
    /* Initialize copyright information */
    p_vpar->sequence.b_copyright_flag = 0;
    p_vpar->sequence.b_original = 0;
    p_vpar->sequence.i_copyright_id = 0;
    p_vpar->sequence.i_copyright_nb = 0;
224

225 226 227
    p_vpar->picture.p_picture = NULL;
    p_vpar->picture.i_current_structure = 0;

228 229
    /* Initialize other properties */
#ifdef STATS
230
    p_vpar->c_loops = 0;
Christophe Massiot's avatar
Christophe Massiot committed
231 232 233 234 235
    p_vpar->c_sequences = 0;
    memset(p_vpar->pc_pictures, 0, sizeof(p_vpar->pc_pictures));
    memset(p_vpar->pc_decoded_pictures, 0, sizeof(p_vpar->pc_decoded_pictures));
    memset(p_vpar->pc_malformed_pictures, 0,
           sizeof(p_vpar->pc_malformed_pictures));
236 237
#endif

238 239
    /* Initialize video FIFO */
    vpar_InitFIFO( p_vpar );
240 241 242 243

    memset( p_vpar->pp_vdec, 0, NB_VDEC*sizeof(vdec_thread_t *) );

#ifdef VDEC_SMP
244
    /* Spawn video_decoder threads */
245
    /* FIXME: modify the number of vdecs at runtime ?? */
246
    for( i_dummy = 0; i_dummy < NB_VDEC; i_dummy++ )
247
    {
248
        if( (p_vpar->pp_vdec[i_dummy] = vdec_CreateThread( p_vpar )) == NULL )
249 250 251
        {
            return( 1 );
        }
252
    }
253 254
#else
    /* Fake a video_decoder thread */
255 256
    if( (p_vpar->pp_vdec[0] = (vdec_thread_t *)malloc(sizeof( vdec_thread_t )))
         == NULL || vdec_InitThread( p_vpar->pp_vdec[0] ) )
257 258 259 260 261 262
    {
        return( 1 );
    }
    p_vpar->pp_vdec[0]->b_die = 0;
    p_vpar->pp_vdec[0]->b_error = 0;
    p_vpar->pp_vdec[0]->p_vpar = p_vpar;
263 264 265 266 267 268 269

    /* Re-nice ourself */
    if( nice(VDEC_NICE) == -1 )
    {
        intf_WarnMsg( 2, "vpar warning : couldn't nice() (%s)\n",
                      strerror(errno) );
    }
270
#endif
271

Stéphane Borel's avatar
 
Stéphane Borel committed
272
    /* Initialize lookup tables */
273
#if defined(MPEG2_COMPLIANT) && !defined(VDEC_DFT)
274 275
    vpar_InitCrop( p_vpar );
#endif
Jean-Marc Dressler's avatar
 
Jean-Marc Dressler committed
276 277 278 279 280
    vpar_InitMbAddrInc( p_vpar );
    vpar_InitDCTTables( p_vpar );
    vpar_InitPMBType( p_vpar );
    vpar_InitBMBType( p_vpar );
    vpar_InitDCTTables( p_vpar );
Stéphane Borel's avatar
 
Stéphane Borel committed
281

282 283 284
    /*
     * Initialize the synchro properties
     */
285
    vpar_SynchroInit( p_vpar );
286

287
    /* Mark thread as running and return */
288
    intf_DbgMsg("vpar debug: InitThread(%p) succeeded\n", p_vpar);
289
    return( 0 );
290 291
}

292
/*****************************************************************************
Stéphane Borel's avatar
Stéphane Borel committed
293
 * RunThread: generic parser thread
294
 *****************************************************************************
295
 * Video parser thread. This function only returns when the thread is
296 297
 * terminated.
 *****************************************************************************/
Stéphane Borel's avatar
Stéphane Borel committed
298
static void RunThread( vpar_thread_t *p_vpar )
299
{
Stéphane Borel's avatar
Stéphane Borel committed
300
    intf_DbgMsg("vpar debug: running video parser thread (%p) (pid == %i)\n", p_vpar, getpid());
301

302 303
    /*
     * Initialize thread
304
     */
Stéphane Borel's avatar
Stéphane Borel committed
305
    p_vpar->b_error = InitThread( p_vpar );
Michel Kaempf's avatar
Michel Kaempf committed
306

Stéphane Borel's avatar
Stéphane Borel committed
307
    p_vpar->b_run = 1;
308 309 310 311 312

    /*
     * Main loop - it is not executed if an error occured during
     * initialization
     */
Stéphane Borel's avatar
Stéphane Borel committed
313
    while( (!p_vpar->b_die) && (!p_vpar->b_error) )
314
    {
315 316 317 318 319
        /* Find the next sequence header in the stream */
        p_vpar->b_error = vpar_NextSequenceHeader( p_vpar );

        while( (!p_vpar->b_die) && (!p_vpar->b_error) )
        {
Christophe Massiot's avatar
Christophe Massiot committed
320 321 322
#ifdef STATS
            p_vpar->c_loops++;
#endif
323 324 325 326 327 328 329
            /* Parse the next sequence, group or picture header */
            if( vpar_ParseHeader( p_vpar ) )
            {
                /* End of sequence */
                break;
            };
        }
330
    }
331 332 333 334

    /*
     * Error loop
     */
Stéphane Borel's avatar
Stéphane Borel committed
335
    if( p_vpar->b_error )
336
    {
337
        ErrorThread( p_vpar );
338 339
    }

Michel Kaempf's avatar
Michel Kaempf committed
340 341
    p_vpar->b_run = 0;

342
    /* End of thread */
Stéphane Borel's avatar
Stéphane Borel committed
343
    EndThread( p_vpar );
344 345
}

346
/*****************************************************************************
347
 * ErrorThread: RunThread() error loop
348
 *****************************************************************************
349 350 351
 * This function is called when an error occured during thread main's loop. The
 * thread can still receive feed, but must be ready to terminate as soon as
 * possible.
352
 *****************************************************************************/
Stéphane Borel's avatar
Stéphane Borel committed
353
static void ErrorThread( vpar_thread_t *p_vpar )
354
{
Michel Kaempf's avatar
Michel Kaempf committed
355 356 357 358 359
    /* We take the lock, because we are going to read/write the start/end
     * indexes of the decoder fifo */
    vlc_mutex_lock( &p_vpar->fifo.data_lock );

    /* Wait until a `die' order is sent */
Stéphane Borel's avatar
Stéphane Borel committed
360
    while( !p_vpar->b_die )
361
    {
Michel Kaempf's avatar
Michel Kaempf committed
362
        /* Trash all received PES packets */
363
        while( !DECODER_FIFO_ISEMPTY(p_vpar->fifo) )
364
        {
365 366
            input_NetlistFreePES( p_vpar->bit_stream.p_input,
                                  DECODER_FIFO_START(p_vpar->fifo) );
367
            DECODER_FIFO_INCSTART( p_vpar->fifo );
368 369
        }

Michel Kaempf's avatar
Michel Kaempf committed
370 371
        /* Waiting for the input thread to put new PES packets in the fifo */
        vlc_cond_wait( &p_vpar->fifo.data_wait, &p_vpar->fifo.data_lock );
372
    }
Michel Kaempf's avatar
Michel Kaempf committed
373 374 375

    /* We can release the lock before leaving */
    vlc_mutex_unlock( &p_vpar->fifo.data_lock );
376 377
}

378
/*****************************************************************************
379
 * EndThread: thread destruction
380
 *****************************************************************************
381
 * This function is called when the thread ends after a sucessful
382
 * initialization.
383
 *****************************************************************************/
Stéphane Borel's avatar
Stéphane Borel committed
384
static void EndThread( vpar_thread_t *p_vpar )
385
{
386
#ifdef VDEC_SMP
387
    int i_dummy;
388
#endif
389

Stéphane Borel's avatar
Stéphane Borel committed
390
    intf_DbgMsg("vpar debug: destroying video parser thread %p\n", p_vpar);
391 392 393

#ifdef DEBUG
    /* Check for remaining PES packets */
394
    /* XXX?? */
395 396
#endif

Christophe Massiot's avatar
Christophe Massiot committed
397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422
#ifdef STATS
    intf_Msg("vpar stats: %d loops among %d sequence(s)\n",
             p_vpar->c_loops, p_vpar->c_sequences);
    intf_Msg("vpar stats: Read %d frames/fields (I %d/P %d/B %d)\n",
             p_vpar->pc_pictures[I_CODING_TYPE]
             + p_vpar->pc_pictures[P_CODING_TYPE]
             + p_vpar->pc_pictures[B_CODING_TYPE],
             p_vpar->pc_pictures[I_CODING_TYPE],
             p_vpar->pc_pictures[P_CODING_TYPE],
             p_vpar->pc_pictures[B_CODING_TYPE]);
    intf_Msg("vpar stats: Decoded %d frames/fields (I %d/P %d/B %d)\n",
             p_vpar->pc_decoded_pictures[I_CODING_TYPE]
             + p_vpar->pc_decoded_pictures[P_CODING_TYPE]
             + p_vpar->pc_decoded_pictures[B_CODING_TYPE],
             p_vpar->pc_decoded_pictures[I_CODING_TYPE],
             p_vpar->pc_decoded_pictures[P_CODING_TYPE],
             p_vpar->pc_decoded_pictures[B_CODING_TYPE]);
    intf_Msg("vpar stats: Read %d malformed frames/fields (I %d/P %d/B %d)\n",
             p_vpar->pc_malformed_pictures[I_CODING_TYPE]
             + p_vpar->pc_malformed_pictures[P_CODING_TYPE]
             + p_vpar->pc_malformed_pictures[B_CODING_TYPE],
             p_vpar->pc_malformed_pictures[I_CODING_TYPE],
             p_vpar->pc_malformed_pictures[P_CODING_TYPE],
             p_vpar->pc_malformed_pictures[B_CODING_TYPE]);
#endif

423
    /* Destroy thread structures allocated by InitThread */
Stéphane Borel's avatar
Stéphane Borel committed
424
//    vout_DestroyStream( p_vpar->p_vout, p_vpar->i_stream );
425
    /* XXX?? */
426

427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444
    /* Dispose of matrices if they have been allocated. */
    if( p_vpar->sequence.intra_quant.b_allocated )
    {
        free( p_vpar->sequence.intra_quant.pi_matrix );
    }
    if( p_vpar->sequence.nonintra_quant.b_allocated )
    {
        free( p_vpar->sequence.nonintra_quant.pi_matrix) ;
    }
    if( p_vpar->sequence.chroma_intra_quant.b_allocated )
    {
        free( p_vpar->sequence.chroma_intra_quant.pi_matrix );
    }
    if( p_vpar->sequence.chroma_nonintra_quant.b_allocated )
    {
        free( p_vpar->sequence.chroma_nonintra_quant.pi_matrix );
    }

445
#ifdef VDEC_SMP
446
    /* Destroy vdec threads */
447
    for( i_dummy = 0; i_dummy < NB_VDEC; i_dummy++ )
448
    {
449 450
        if( p_vpar->pp_vdec[i_dummy] != NULL )
            vdec_DestroyThread( p_vpar->pp_vdec[i_dummy] );
451 452 453
        else
            break;
    }
454 455 456
#else
    free( p_vpar->pp_vdec[0] );
#endif
457

Michel Kaempf's avatar
Michel Kaempf committed
458 459
    free( p_vpar );

Stéphane Borel's avatar
Stéphane Borel committed
460
    intf_DbgMsg("vpar debug: EndThread(%p)\n", p_vpar);
461
}