video_parser.c 13.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
#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
#include "stream_control.h"
#include "input_ext-dec.h"

50 51
#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

/*
 * Local prototypes
 */
Stéphane Borel's avatar
Stéphane Borel committed
66 67 68 69
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 );
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
 *****************************************************************************/
79
vlc_thread_t vpar_CreateThread( vdec_config_t * p_config )
80
{
Stéphane Borel's avatar
Stéphane Borel committed
81
    vpar_thread_t *     p_vpar;
82

83
    intf_DbgMsg( "vpar debug: creating video parser thread\n" );
84 85

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

    /*
     * Initialize the thread properties
     */
Stéphane Borel's avatar
Stéphane Borel committed
96 97
    p_vpar->b_die = 0;
    p_vpar->b_error = 0;
98 99
    p_vpar->p_fifo = p_config->decoder_config.p_decoder_fifo;
    p_vpar->p_config = p_config;
100

101
    p_vpar->p_vout = p_config->p_vout;
Jean-Marc Dressler's avatar
 
Jean-Marc Dressler committed
102

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

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

/* following functions are local */

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

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

133 134
    p_vpar->p_config->decoder_config.pf_init_bit_stream( &p_vpar->bit_stream,
        p_vpar->p_config->decoder_config.p_decoder_fifo );
135

136
    /* Initialize parsing data */
137 138 139 140 141 142
    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;
143

Stéphane Borel's avatar
 
Stéphane Borel committed
144 145 146 147 148
    /* 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;
149

150 151 152
    p_vpar->picture.p_picture = NULL;
    p_vpar->picture.i_current_structure = 0;

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

163 164
    /* Initialize video FIFO */
    vpar_InitFIFO( p_vpar );
165 166 167 168

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

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

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

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

207 208 209
    /*
     * Initialize the synchro properties
     */
210
    vpar_SynchroInit( p_vpar );
211

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

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

227 228
    /*
     * Initialize thread
229
     */
Stéphane Borel's avatar
Stéphane Borel committed
230
    p_vpar->b_error = InitThread( p_vpar );
Michel Kaempf's avatar
Michel Kaempf committed
231

Stéphane Borel's avatar
Stéphane Borel committed
232
    p_vpar->b_run = 1;
233 234 235 236 237

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

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

    /*
     * Error loop
     */
Stéphane Borel's avatar
Stéphane Borel committed
260
    if( p_vpar->b_error )
261
    {
262
        ErrorThread( p_vpar );
263 264
    }

Michel Kaempf's avatar
Michel Kaempf committed
265 266
    p_vpar->b_run = 0;

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

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

    /* Wait until a `die' order is sent */
285
    while( !p_vpar->p_fifo->b_die )
286
    {
Michel Kaempf's avatar
Michel Kaempf committed
287
        /* Trash all received PES packets */
288
        while( !DECODER_FIFO_ISEMPTY(*p_vpar->p_fifo) )
289
        {
290 291 292
            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 );
293 294
        }

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

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

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

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

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

Christophe Massiot's avatar
Christophe Massiot committed
322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345
#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]);
Christophe Massiot's avatar
Christophe Massiot committed
346
#define S   p_vpar->sequence
347
    intf_Msg("vpar info: %s stream (%dx%d), %d pi/s\n",
Christophe Massiot's avatar
Christophe Massiot committed
348
             S.b_mpeg2 ? "MPEG-2" : "MPEG-1",
349
             S.i_width, S.i_height, S.i_frame_rate/1001);
Christophe Massiot's avatar
Christophe Massiot committed
350 351 352 353
    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
354 355
#endif

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

360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377
    /* 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 );
    }

378
#ifdef VDEC_SMP
379
    /* Destroy vdec threads */
380
    for( i_dummy = 0; i_dummy < NB_VDEC; i_dummy++ )
381
    {
382 383
        if( p_vpar->pp_vdec[i_dummy] != NULL )
            vdec_DestroyThread( p_vpar->pp_vdec[i_dummy] );
384 385 386
        else
            break;
    }
387 388 389
#else
    free( p_vpar->pp_vdec[0] );
#endif
390

Michel Kaempf's avatar
Michel Kaempf committed
391 392
    free( p_vpar );

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