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

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

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

30 31 32 33
#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" */
34 35 36

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

/* following functions are local */

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

    return( 0 );
}
#endif

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

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

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

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

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

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

225 226
    /* Initialize other properties */
#ifdef STATS
227
    p_vpar->c_loops = 0;
Stéphane Borel's avatar
Stéphane Borel committed
228 229 230 231 232 233 234 235 236
    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;
237 238
#endif

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

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

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

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

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

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

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

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

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

#ifdef MEUUH_SYNCHRO
Christophe Massiot's avatar
Christophe Massiot committed
310 311 312 313 314 315
    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
316

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

321 322
    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;
323 324 325 326
    p_vpar->synchro.i_p_count = 0;
    p_vpar->synchro.i_b_count = 0;
    p_vpar->synchro.i_i_count = 0;
#endif
327

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

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

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

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

    /*
     * Main loop - it is not executed if an error occured during
     * initialization
     */
Stéphane Borel's avatar
Stéphane Borel committed
354
    while( (!p_vpar->b_die) && (!p_vpar->b_error) )
355
    {
356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371
        /* 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;
            };
        }
372
    }
373 374 375 376

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

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

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

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

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

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

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

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

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

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

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

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

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

Stéphane Borel's avatar
Stéphane Borel committed
476
    intf_DbgMsg("vpar debug: EndThread(%p)\n", p_vpar);
477
}
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 503 504 505 506 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

/*****************************************************************************
 * 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;

          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;

}