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

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

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

32 33 34 35
#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" */
36 37
#include <errno.h>
#include <string.h>
38

39 40 41 42
#ifdef STATS
#  include <sys/times.h>
#endif

43 44
#include "config.h"
#include "common.h"
45
#include "threads.h"
46
#include "mtime.h"
47
#include "plugins.h"
48 49

#include "intf_msg.h"
50
#include "debug.h"                 /* XXX?? temporaire, requis par netlist.h */
51

52 53 54
#include "stream_control.h"
#include "input_ext-dec.h"

55 56
#include "video.h"
#include "video_output.h"
57 58

#include "vdec_idct.h"
59
#include "video_decoder.h"
60 61 62 63
#include "vdec_motion.h"

#include "vpar_blocks.h"
#include "vpar_headers.h"
64
#include "vpar_synchro.h"
Stéphane Borel's avatar
Stéphane Borel committed
65
#include "video_parser.h"
66
#include "video_fifo.h"
67 68 69 70

/*
 * Local prototypes
 */
Stéphane Borel's avatar
Stéphane Borel committed
71 72 73 74
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 );
75

76
/*****************************************************************************
Stéphane Borel's avatar
Stéphane Borel committed
77
 * vpar_CreateThread: create a generic parser thread
78
 *****************************************************************************
Stéphane Borel's avatar
Stéphane Borel committed
79
 * This function creates a new video parser thread, and returns a pointer
80 81
 * to its description. On error, it returns NULL.
 * Following configuration properties are used:
82
 * XXX??
83
 *****************************************************************************/
84
vlc_thread_t vpar_CreateThread( vdec_config_t * p_config )
85
{
Stéphane Borel's avatar
Stéphane Borel committed
86
    vpar_thread_t *     p_vpar;
87

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

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

    /*
     * Initialize the thread properties
     */
101 102
    p_vpar->p_fifo = p_config->decoder_config.p_decoder_fifo;
    p_vpar->p_config = p_config;
103

104
    p_vpar->p_vout = p_config->p_vout;
Jean-Marc Dressler's avatar
 
Jean-Marc Dressler committed
105

Stéphane Borel's avatar
Stéphane Borel committed
106
    /* Spawn the video parser thread */
107 108
    if ( vlc_thread_create( &p_vpar->thread_id, "video parser",
                            (vlc_thread_func_t)RunThread, (void *)p_vpar ) )
109
    {
Stéphane Borel's avatar
Stéphane Borel committed
110 111
        intf_ErrMsg("vpar error: can't spawn video parser thread\n");
        free( p_vpar );
112
        return( 0 );
113 114
    }

Stéphane Borel's avatar
Stéphane Borel committed
115
    intf_DbgMsg("vpar debug: video parser thread (%p) created\n", p_vpar);
116
    return( p_vpar->thread_id );
117 118 119 120
}

/* following functions are local */

121
/*****************************************************************************
Stéphane Borel's avatar
Stéphane Borel committed
122
 * InitThread: initialize vpar output thread
123
 *****************************************************************************
124 125 126
 * 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.
127
 *****************************************************************************/
Stéphane Borel's avatar
Stéphane Borel committed
128
static int InitThread( vpar_thread_t *p_vpar )
129
{
Michel Kaempf's avatar
Michel Kaempf committed
130 131 132 133
#ifdef VDEC_SMP
    int i_dummy;
#endif

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

136 137
    p_vpar->p_config->decoder_config.pf_init_bit_stream( &p_vpar->bit_stream,
        p_vpar->p_config->decoder_config.p_decoder_fifo );
138

139
    /* Initialize parsing data */
140 141 142 143 144 145
    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;
146

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

153 154 155
    p_vpar->picture.p_picture = NULL;
    p_vpar->picture.i_current_structure = 0;

156 157
    /* Initialize other properties */
#ifdef STATS
158
    p_vpar->c_loops = 0;
Christophe Massiot's avatar
Christophe Massiot committed
159 160 161 162 163
    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));
164 165
#endif

166 167
    /* Initialize video FIFO */
    vpar_InitFIFO( p_vpar );
168 169 170 171

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

#ifdef VDEC_SMP
172
    /* Spawn video_decoder threads */
173
    /* FIXME: modify the number of vdecs at runtime ?? */
174
    for( i_dummy = 0; i_dummy < NB_VDEC; i_dummy++ )
175
    {
176
        if( (p_vpar->pp_vdec[i_dummy] = vdec_CreateThread( p_vpar )) == NULL )
177 178 179
        {
            return( 1 );
        }
180
    }
181 182
#else
    /* Fake a video_decoder thread */
183 184
    if( (p_vpar->pp_vdec[0] = (vdec_thread_t *)malloc(sizeof( vdec_thread_t )))
         == NULL || vdec_InitThread( p_vpar->pp_vdec[0] ) )
185 186 187 188 189 190
    {
        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;
191 192 193 194 195 196 197

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

Stéphane Borel's avatar
 
Stéphane Borel committed
200
    /* Initialize lookup tables */
201
#if defined(MPEG2_COMPLIANT) && !defined(VDEC_DFT)
202 203
    vpar_InitCrop( p_vpar );
#endif
Jean-Marc Dressler's avatar
 
Jean-Marc Dressler committed
204 205 206 207 208
    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
209

210 211 212
    /*
     * Initialize the synchro properties
     */
213
    vpar_SynchroInit( p_vpar );
214

215
    /* Mark thread as running and return */
216
    intf_DbgMsg("vpar debug: InitThread(%p) succeeded\n", p_vpar);
217
    return( 0 );
218 219
}

220
/*****************************************************************************
Stéphane Borel's avatar
Stéphane Borel committed
221
 * RunThread: generic parser thread
222
 *****************************************************************************
223
 * Video parser thread. This function only returns when the thread is
224 225
 * terminated.
 *****************************************************************************/
Stéphane Borel's avatar
Stéphane Borel committed
226
static void RunThread( vpar_thread_t *p_vpar )
227
{
Stéphane Borel's avatar
Stéphane Borel committed
228
    intf_DbgMsg("vpar debug: running video parser thread (%p) (pid == %i)\n", p_vpar, getpid());
229

230 231
    /*
     * Initialize thread
232
     */
233
    p_vpar->p_fifo->b_error = InitThread( p_vpar );
234 235 236 237 238

    /*
     * Main loop - it is not executed if an error occured during
     * initialization
     */
239
    while( (!p_vpar->p_fifo->b_die) && (!p_vpar->p_fifo->b_error) )
240
    {
241
        /* Find the next sequence header in the stream */
242
        p_vpar->p_fifo->b_error = vpar_NextSequenceHeader( p_vpar );
243

244
        while( (!p_vpar->p_fifo->b_die) && (!p_vpar->p_fifo->b_error) )
245
        {
Christophe Massiot's avatar
Christophe Massiot committed
246 247 248
#ifdef STATS
            p_vpar->c_loops++;
#endif
249 250 251 252 253 254 255
            /* Parse the next sequence, group or picture header */
            if( vpar_ParseHeader( p_vpar ) )
            {
                /* End of sequence */
                break;
            };
        }
256
    }
257 258 259 260

    /*
     * Error loop
     */
261
    if( p_vpar->p_fifo->b_error )
262
    {
263
        ErrorThread( p_vpar );
264 265 266
    }

    /* End of thread */
Stéphane Borel's avatar
Stéphane Borel committed
267
    EndThread( p_vpar );
268 269
}

270
/*****************************************************************************
271
 * ErrorThread: RunThread() error loop
272
 *****************************************************************************
273 274 275
 * 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.
276
 *****************************************************************************/
Stéphane Borel's avatar
Stéphane Borel committed
277
static void ErrorThread( vpar_thread_t *p_vpar )
278
{
Michel Kaempf's avatar
Michel Kaempf committed
279 280
    /* We take the lock, because we are going to read/write the start/end
     * indexes of the decoder fifo */
281
    vlc_mutex_lock( &p_vpar->p_fifo->data_lock );
Michel Kaempf's avatar
Michel Kaempf committed
282 283

    /* Wait until a `die' order is sent */
284
    while( !p_vpar->p_fifo->b_die )
285
    {
Michel Kaempf's avatar
Michel Kaempf committed
286
        /* Trash all received PES packets */
287
        while( !DECODER_FIFO_ISEMPTY(*p_vpar->p_fifo) )
288
        {
289 290 291
            p_vpar->p_fifo->pf_delete_pes( p_vpar->p_fifo->p_packets_mgt,
                                  DECODER_FIFO_START(*p_vpar->p_fifo) );
            DECODER_FIFO_INCSTART( *p_vpar->p_fifo );
292 293
        }

Michel Kaempf's avatar
Michel Kaempf committed
294
        /* Waiting for the input thread to put new PES packets in the fifo */
295
        vlc_cond_wait( &p_vpar->p_fifo->data_wait, &p_vpar->p_fifo->data_lock );
296
    }
Michel Kaempf's avatar
Michel Kaempf committed
297 298

    /* We can release the lock before leaving */
299
    vlc_mutex_unlock( &p_vpar->p_fifo->data_lock );
300 301
}

302
/*****************************************************************************
303
 * EndThread: thread destruction
304
 *****************************************************************************
305
 * This function is called when the thread ends after a sucessful
306
 * initialization.
307
 *****************************************************************************/
Stéphane Borel's avatar
Stéphane Borel committed
308
static void EndThread( vpar_thread_t *p_vpar )
309
{
310
#ifdef VDEC_SMP
311
    int i_dummy;
312
#endif
313

Stéphane Borel's avatar
Stéphane Borel committed
314
    intf_DbgMsg("vpar debug: destroying video parser thread %p\n", p_vpar);
315 316 317

#ifdef DEBUG
    /* Check for remaining PES packets */
318
    /* XXX?? */
319 320
#endif

Christophe Massiot's avatar
Christophe Massiot committed
321 322 323
#ifdef STATS
    intf_Msg("vpar stats: %d loops among %d sequence(s)\n",
             p_vpar->c_loops, p_vpar->c_sequences);
324 325 326 327 328 329 330 331 332

    {
        struct tms cpu_usage;
        times( &cpu_usage );

        intf_Msg("vpar stats: cpu usage (user: %d, system: %d)\n",
                 cpu_usage.tms_utime, cpu_usage.tms_stime);
    }

Christophe Massiot's avatar
Christophe Massiot committed
333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353
    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]);
Christophe Massiot's avatar
Christophe Massiot committed
354
#define S   p_vpar->sequence
355
    intf_Msg("vpar info: %s stream (%dx%d), %d pi/s\n",
Christophe Massiot's avatar
Christophe Massiot committed
356
             S.b_mpeg2 ? "MPEG-2" : "MPEG-1",
357
             S.i_width, S.i_height, S.i_frame_rate/1001);
Christophe Massiot's avatar
Christophe Massiot committed
358 359 360 361
    intf_Msg("vpar info: %s, %s, matrix_coeff: %d\n",
             S.b_progressive ? "Progressive" : "Non-progressive",
             S.i_scalable_mode ? "scalable" : "non-scalable",
             S.i_matrix_coefficients);
Christophe Massiot's avatar
Christophe Massiot committed
362 363
#endif

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

368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385
    /* 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 );
    }

386
#ifdef VDEC_SMP
387
    /* Destroy vdec threads */
388
    for( i_dummy = 0; i_dummy < NB_VDEC; i_dummy++ )
389
    {
390 391
        if( p_vpar->pp_vdec[i_dummy] != NULL )
            vdec_DestroyThread( p_vpar->pp_vdec[i_dummy] );
392 393 394
        else
            break;
    }
395 396 397
#else
    free( p_vpar->pp_vdec[0] );
#endif
398

Michel Kaempf's avatar
Michel Kaempf committed
399 400
    free( p_vpar );

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