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
 *****************************************************************************
 * Copyright (C) 1999, 2000 VideoLAN
5
 * $Id: video_parser.c,v 1.57 2000/12/21 17:19:54 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
/*****************************************************************************
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
#include <errno.h>
#include <string.h>
36

37 38 39 40
#ifdef STATS
#  include <sys/times.h>
#endif

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

#include "intf_msg.h"

49 50 51
#include "stream_control.h"
#include "input_ext-dec.h"

52 53
#include "video.h"
#include "video_output.h"
54

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

59 60 61 62 63
#include "../video_decoder/vpar_blocks.h"
#include "../video_decoder/vpar_headers.h"
#include "../video_decoder/vpar_synchro.h"
#include "../video_decoder/video_parser.h"
#include "../video_decoder/video_fifo.h"
64 65 66 67

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

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

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

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

    /*
     * Initialize the thread properties
     */
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
     */
230
    p_vpar->p_fifo->b_error = InitThread( p_vpar );
231 232 233 234 235

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

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

    /*
     * Error loop
     */
258
    if( p_vpar->p_fifo->b_error )
259
    {
260
        ErrorThread( p_vpar );
261 262 263
    }

    /* End of thread */
Stéphane Borel's avatar
Stéphane Borel committed
264
    EndThread( p_vpar );
265 266
}

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

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

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

    /* We can release the lock before leaving */
296
    vlc_mutex_unlock( &p_vpar->p_fifo->data_lock );
297 298
}

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

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

Christophe Massiot's avatar
Christophe Massiot committed
313 314 315
#ifdef STATS
    intf_Msg("vpar stats: %d loops among %d sequence(s)\n",
             p_vpar->c_loops, p_vpar->c_sequences);
316 317 318 319 320 321 322 323 324

    {
        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
325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345
    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 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373
    /* 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 );
    }

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

387
    free( p_vpar->p_config );
Michel Kaempf's avatar
Michel Kaempf committed
388 389
    free( p_vpar );

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