video_parser.c 17.3 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 37

#include "config.h"
#include "common.h"
38
#include "threads.h"
39
#include "mtime.h"
40
#include "plugins.h"
41 42

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

#include "input.h"
#include "input_netlist.h"
#include "decoder_fifo.h"
#include "video.h"
#include "video_output.h"
50 51

#include "vdec_idct.h"
52
#include "video_decoder.h"
53 54 55 56
#include "vdec_motion.h"

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

/*
 * Local prototypes
 */
//static int      CheckConfiguration  ( video_cfg_t *p_cfg );
Stéphane Borel's avatar
Stéphane Borel committed
65 66 67 68
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 );
69
static int      SynchroType         ( );
70

71
/*****************************************************************************
Stéphane Borel's avatar
Stéphane Borel committed
72
 * vpar_CreateThread: create a generic parser thread
73
 *****************************************************************************
Stéphane Borel's avatar
Stéphane Borel committed
74
 * This function creates a new video parser thread, and returns a pointer
75 76
 * to its description. On error, it returns NULL.
 * Following configuration properties are used:
77
 * XXX??
78
 *****************************************************************************/
Jean-Marc Dressler's avatar
 
Jean-Marc Dressler committed
79 80 81
#include "main.h"
#include "interface.h"
extern main_t* p_main;
Stéphane Borel's avatar
Stéphane Borel committed
82
vpar_thread_t * vpar_CreateThread( /* video_cfg_t *p_cfg, */ input_thread_t *p_input /*,
83 84
                                   vout_thread_t *p_vout, int *pi_status */ )
{
Stéphane Borel's avatar
Stéphane Borel committed
85
    vpar_thread_t *     p_vpar;
86

87
    intf_DbgMsg( "vpar debug: creating video parser thread\n" );
88 89

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

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

    /*
     * Initialize the input properties
     */
106 107
    /* 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
108 109 110 111
    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;
112
    /* Initialize the bit stream structure */
Stéphane Borel's avatar
Stéphane Borel committed
113
    p_vpar->bit_stream.p_input = p_input;
114
    p_vpar->bit_stream.p_decoder_fifo = &p_vpar->fifo;
Stéphane Borel's avatar
Stéphane Borel committed
115 116
    p_vpar->bit_stream.fifo.buffer = 0;
    p_vpar->bit_stream.fifo.i_available = 0;
117

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

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

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

134
/*****************************************************************************
Stéphane Borel's avatar
Stéphane Borel committed
135
 * vpar_DestroyThread: destroy a generic parser thread
136
 *****************************************************************************
137 138 139
 * 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.
140
 *****************************************************************************/
141
void vpar_DestroyThread( vpar_thread_t *p_vpar /*, int *pi_status */ )
142
{
143 144
    intf_DbgMsg( "vpar debug: requesting termination of "
                 "video parser thread %p\n", p_vpar);
145 146

    /* Ask thread to kill itself */
Stéphane Borel's avatar
Stéphane Borel committed
147 148 149 150 151
    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) );
152

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

/* following functions are local */

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

    return( 0 );
}
#endif

175
/*****************************************************************************
Stéphane Borel's avatar
Stéphane Borel committed
176
 * InitThread: initialize vpar output thread
177
 *****************************************************************************
178 179 180
 * 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.
181
 *****************************************************************************/
Stéphane Borel's avatar
Stéphane Borel committed
182
static int InitThread( vpar_thread_t *p_vpar )
183
{
Michel Kaempf's avatar
Michel Kaempf committed
184 185 186 187
#ifdef VDEC_SMP
    int i_dummy;
#endif

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

    /* 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
192
    vlc_mutex_lock( &p_vpar->fifo.data_lock );
193
    while ( DECODER_FIFO_ISEMPTY(p_vpar->fifo) )
194
    {
Michel Kaempf's avatar
Michel Kaempf committed
195 196 197 198 199
        if ( p_vpar->b_die )
        {
            vlc_mutex_unlock( &p_vpar->fifo.data_lock );
            return( 1 );
        }
Stéphane Borel's avatar
Stéphane Borel committed
200
        vlc_cond_wait( &p_vpar->fifo.data_wait, &p_vpar->fifo.data_lock );
201
    }
202
    p_vpar->bit_stream.p_ts = DECODER_FIFO_START( p_vpar->fifo )->p_first_ts;
203 204 205 206
    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
207
    vlc_mutex_unlock( &p_vpar->fifo.data_lock );
208

209
    /* Initialize parsing data */
210 211 212 213 214 215
    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;
216

Stéphane Borel's avatar
 
Stéphane Borel committed
217 218 219 220 221
    /* 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;
222

223 224 225
    p_vpar->picture.p_picture = NULL;
    p_vpar->picture.i_current_structure = 0;

226 227
    /* Initialize other properties */
#ifdef STATS
228
    p_vpar->c_loops = 0;
Stéphane Borel's avatar
Stéphane Borel committed
229 230 231 232 233 234 235 236 237
    p_vpar->c_idle_loops = 0;
    p_vpar->c_pictures = 0;
    p_vpar->c_i_pictures = 0;
    p_vpar->c_p_pictures = 0;
    p_vpar->c_b_pictures = 0;
    p_vpar->c_decoded_pictures = 0;
    p_vpar->c_decoded_i_pictures = 0;
    p_vpar->c_decoded_p_pictures = 0;
    p_vpar->c_decoded_b_pictures = 0;
238 239
#endif

240 241
    /* Initialize video FIFO */
    vpar_InitFIFO( p_vpar );
242 243 244 245

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

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

Stéphane Borel's avatar
 
Stéphane Borel committed
267
    /* Initialize lookup tables */
268
#if defined(MPEG2_COMPLIANT) && !defined(VDEC_DFT)
269 270
    vpar_InitCrop( p_vpar );
#endif
Jean-Marc Dressler's avatar
 
Jean-Marc Dressler committed
271 272 273 274 275
    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
276

277 278 279
    /*
     * Initialize the synchro properties
     */
280
#ifdef SAM_SYNCHRO
281 282 283 284
    /* Get an possible synchro algorithm */
    p_vpar->synchro.i_type = SynchroType();

    /* last seen PTS */
285 286
    p_vpar->synchro.i_last_pts = 0;

287
    /* for i frames */
288 289 290
    p_vpar->synchro.i_last_seen_I_pts = 0;
    p_vpar->synchro.i_last_kept_I_pts = 0;

291
    /* the fifo */
292 293 294
    p_vpar->synchro.i_start  = 0;
    p_vpar->synchro.i_stop   = 0;

295
    /* mean decoding time - at least 200 ms for a slow machine */
296 297
    p_vpar->synchro.i_delay            = 200000;
    p_vpar->synchro.i_theorical_delay  = 40000; /* 25 fps */
298
    /* assume we can display all Is and 2 Ps */
Sam Hocevar's avatar
Sam Hocevar committed
299
    p_vpar->synchro.b_all_I = 1 << 10;
300
    p_vpar->synchro.b_all_P = 0;
Sam Hocevar's avatar
Sam Hocevar committed
301
    p_vpar->synchro.displayable_p = 2 << 10;
302
    p_vpar->synchro.b_all_B = 0;
303
    p_vpar->synchro.displayable_b = 0;
304
    p_vpar->synchro.b_dropped_last = 0;
305
    /* assume there were about 3 P and 6 B images between I's */
Sam Hocevar's avatar
Sam Hocevar committed
306 307
    p_vpar->synchro.i_P_seen = p_vpar->synchro.i_P_kept = 1 << 10;
    p_vpar->synchro.i_B_seen = p_vpar->synchro.i_B_kept = 1 << 10;
308 309 310
#endif

#ifdef MEUUH_SYNCHRO
Christophe Massiot's avatar
Christophe Massiot committed
311 312 313 314 315 316
    p_vpar->synchro.kludge_level = 5;
    p_vpar->synchro.kludge_nbp = p_vpar->synchro.kludge_p = 5;
    p_vpar->synchro.kludge_nbb = p_vpar->synchro.kludge_b = 6;
    p_vpar->synchro.kludge_b = 0;
    p_vpar->synchro.kludge_prevdate = 0;
#endif
317

318 319 320
#ifdef POLUX_SYNCHRO
    p_vpar->synchro.i_current_frame_date = 0;
    p_vpar->synchro.i_backward_frame_date = 0;
321

322 323
    p_vpar->synchro.r_p_average = p_vpar->synchro.i_p_nb = 6;
    p_vpar->synchro.r_b_average = p_vpar->synchro.i_b_nb = 6;
324 325 326 327
    p_vpar->synchro.i_p_count = 0;
    p_vpar->synchro.i_b_count = 0;
    p_vpar->synchro.i_i_count = 0;
#endif
328

329
    /* Mark thread as running and return */
330
    intf_DbgMsg("vpar debug: InitThread(%p) succeeded\n", p_vpar);
331
    return( 0 );
332 333
}

334
/*****************************************************************************
Stéphane Borel's avatar
Stéphane Borel committed
335
 * RunThread: generic parser thread
336
 *****************************************************************************
337
 * Video parser thread. This function only returns when the thread is
338 339
 * terminated.
 *****************************************************************************/
Stéphane Borel's avatar
Stéphane Borel committed
340
static void RunThread( vpar_thread_t *p_vpar )
341
{
Stéphane Borel's avatar
Stéphane Borel committed
342
    intf_DbgMsg("vpar debug: running video parser thread (%p) (pid == %i)\n", p_vpar, getpid());
343

344 345
    /*
     * Initialize thread
346
     */
Stéphane Borel's avatar
Stéphane Borel committed
347
    p_vpar->b_error = InitThread( p_vpar );
Michel Kaempf's avatar
Michel Kaempf committed
348

Stéphane Borel's avatar
Stéphane Borel committed
349
    p_vpar->b_run = 1;
350 351 352 353 354

    /*
     * Main loop - it is not executed if an error occured during
     * initialization
     */
Stéphane Borel's avatar
Stéphane Borel committed
355
    while( (!p_vpar->b_die) && (!p_vpar->b_error) )
356
    {
357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372
        /* Find the next sequence header in the stream */
        p_vpar->b_error = vpar_NextSequenceHeader( p_vpar );

#ifdef STATS
        p_vpar->c_sequences++;
#endif

        while( (!p_vpar->b_die) && (!p_vpar->b_error) )
        {
            /* Parse the next sequence, group or picture header */
            if( vpar_ParseHeader( p_vpar ) )
            {
                /* End of sequence */
                break;
            };
        }
373
    }
374 375 376 377

    /*
     * Error loop
     */
Stéphane Borel's avatar
Stéphane Borel committed
378
    if( p_vpar->b_error )
379
    {
380
        ErrorThread( p_vpar );
381 382
    }

Michel Kaempf's avatar
Michel Kaempf committed
383 384
    p_vpar->b_run = 0;

385
    /* End of thread */
Stéphane Borel's avatar
Stéphane Borel committed
386
    EndThread( p_vpar );
387 388
}

389
/*****************************************************************************
390
 * ErrorThread: RunThread() error loop
391
 *****************************************************************************
392 393 394
 * 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.
395
 *****************************************************************************/
Stéphane Borel's avatar
Stéphane Borel committed
396
static void ErrorThread( vpar_thread_t *p_vpar )
397
{
Michel Kaempf's avatar
Michel Kaempf committed
398 399 400 401 402
    /* 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
403
    while( !p_vpar->b_die )
404
    {
Michel Kaempf's avatar
Michel Kaempf committed
405
        /* Trash all received PES packets */
406
        while( !DECODER_FIFO_ISEMPTY(p_vpar->fifo) )
407
        {
408 409
            input_NetlistFreePES( p_vpar->bit_stream.p_input,
                                  DECODER_FIFO_START(p_vpar->fifo) );
410
            DECODER_FIFO_INCSTART( p_vpar->fifo );
411 412
        }

Michel Kaempf's avatar
Michel Kaempf committed
413 414
        /* 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 );
415
    }
Michel Kaempf's avatar
Michel Kaempf committed
416 417 418

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

421
/*****************************************************************************
422
 * EndThread: thread destruction
423
 *****************************************************************************
424
 * This function is called when the thread ends after a sucessful
425
 * initialization.
426
 *****************************************************************************/
Stéphane Borel's avatar
Stéphane Borel committed
427
static void EndThread( vpar_thread_t *p_vpar )
428
{
429
#ifdef VDEC_SMP
430
    int i_dummy;
431
#endif
432

Stéphane Borel's avatar
Stéphane Borel committed
433
    intf_DbgMsg("vpar debug: destroying video parser thread %p\n", p_vpar);
434 435 436

#ifdef DEBUG
    /* Check for remaining PES packets */
437
    /* XXX?? */
438 439 440
#endif

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

444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461
    /* 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 );
    }

462
#ifdef VDEC_SMP
463
    /* Destroy vdec threads */
464
    for( i_dummy = 0; i_dummy < NB_VDEC; i_dummy++ )
465
    {
466 467
        if( p_vpar->pp_vdec[i_dummy] != NULL )
            vdec_DestroyThread( p_vpar->pp_vdec[i_dummy] );
468 469 470
        else
            break;
    }
471 472 473
#else
    free( p_vpar->pp_vdec[0] );
#endif
474

Michel Kaempf's avatar
Michel Kaempf committed
475 476
    free( p_vpar );

Stéphane Borel's avatar
Stéphane Borel committed
477
    intf_DbgMsg("vpar debug: EndThread(%p)\n", p_vpar);
478
}
479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502

/*****************************************************************************
 * SynchroType: Get the user's synchro type
 *****************************************************************************
 * This function is called at initialization.
 *****************************************************************************/
static int SynchroType( )
{
    char * psz_synchro = main_GetPszVariable( VPAR_SYNCHRO_VAR, NULL );

    if( psz_synchro == NULL )
    {
        return VPAR_SYNCHRO_DEFAULT;
    }

    switch( *psz_synchro++ )
    {
      case 'i':
      case 'I':
        switch( *psz_synchro++ )
        {
          case '\0':
            return VPAR_SYNCHRO_I;

503 504 505 506
          case '+':
            if( *psz_synchro ) return 0;
            return VPAR_SYNCHRO_Iplus;

507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536
          case 'p':
          case 'P':
            switch( *psz_synchro++ )
            {
              case '\0':
                return VPAR_SYNCHRO_IP;

              case '+':
                if( *psz_synchro ) return 0;
                return VPAR_SYNCHRO_IPplus;

              case 'b':
              case 'B':
                if( *psz_synchro ) return 0;
                return VPAR_SYNCHRO_IPB;

              default:
                return VPAR_SYNCHRO_DEFAULT;
                
            }

          default:
            return VPAR_SYNCHRO_DEFAULT;
        }
    }

    return VPAR_SYNCHRO_DEFAULT;

}