video_decoder.c 10.5 KB
Newer Older
Michel Kaempf's avatar
Michel Kaempf committed
1 2 3 4 5 6 7 8 9 10 11 12 13
/*******************************************************************************
 * video_decoder.c : video decoder thread
 * (c)1999 VideoLAN
 *******************************************************************************/

/* ?? passer en terminate/destroy avec les signaux supplmentaires */

/*******************************************************************************
 * Preamble
 *******************************************************************************/
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
14
#include <unistd.h>
Michel Kaempf's avatar
Michel Kaempf committed
15 16 17 18 19 20 21 22
#include <string.h>
#include <sys/uio.h>
#include <X11/Xlib.h>
#include <X11/extensions/XShm.h>

#include "config.h"
#include "common.h"
#include "mtime.h"
23
#include "vlc_thread.h"
Michel Kaempf's avatar
Michel Kaempf committed
24 25 26 27 28 29 30 31 32

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

#include "input.h"
#include "input_netlist.h"
#include "decoder_fifo.h"
#include "video.h"
#include "video_output.h"
33

34
#include "vdec_idct.h"
Michel Kaempf's avatar
Michel Kaempf committed
35
#include "video_decoder.h"
36 37 38 39 40
#include "vdec_motion.h"

#include "vpar_blocks.h"
#include "vpar_headers.h"
#include "video_fifo.h"
41
#include "vpar_synchro.h"
42
#include "video_parser.h"
Michel Kaempf's avatar
Michel Kaempf committed
43 44 45 46 47 48 49 50

/*
 * Local prototypes
 */
static int      InitThread          ( vdec_thread_t *p_vdec );
static void     RunThread           ( vdec_thread_t *p_vdec );
static void     ErrorThread         ( vdec_thread_t *p_vdec );
static void     EndThread           ( vdec_thread_t *p_vdec );
51 52
static void     DecodeMacroblock    ( vdec_thread_t *p_vdec,
                                      macroblock_t * p_mb );
Michel Kaempf's avatar
Michel Kaempf committed
53 54

/*******************************************************************************
55
 * vdec_CreateThread: create a video decoder thread
Michel Kaempf's avatar
Michel Kaempf committed
56 57 58 59 60 61
 *******************************************************************************
 * This function creates a new video decoder thread, and returns a pointer
 * to its description. On error, it returns NULL.
 * Following configuration properties are used:
 * ??
 *******************************************************************************/
62
vdec_thread_t * vdec_CreateThread( vpar_thread_t *p_vpar /*, int *pi_status */ )
Michel Kaempf's avatar
Michel Kaempf committed
63
{
64 65 66 67 68 69 70
    vdec_thread_t *     p_vdec;

    intf_DbgMsg("vdec debug: creating video decoder thread\n");

    /* Allocate the memory needed to store the thread's structure */
    if ( (p_vdec = (vdec_thread_t *)malloc( sizeof(vdec_thread_t) )) == NULL )
    {
71
        intf_ErrMsg("vdec error: not enough memory for vdec_CreateThread() to create the new thread\n");
72 73 74 75 76 77 78 79 80 81
        return( NULL );
    }

    /*
     * Initialize the thread properties
     */
    p_vdec->b_die = 0;
    p_vdec->b_error = 0;

    /*
82
     * Initialize the parser properties
83
     */
84
    p_vdec->p_vpar = p_vpar;
85 86

    /* Spawn the video decoder thread */
87 88
    if ( vlc_thread_create(&p_vdec->thread_id, "video decoder",
         (vlc_thread_func)RunThread, (void *)p_vdec) )
89 90 91 92 93 94 95 96
    {
        intf_ErrMsg("vdec error: can't spawn video decoder thread\n");
        free( p_vdec );
        return( NULL );
    }

    intf_DbgMsg("vdec debug: video decoder thread (%p) created\n", p_vdec);
    return( p_vdec );
Michel Kaempf's avatar
Michel Kaempf committed
97 98 99
}

/*******************************************************************************
100
 * vdec_DestroyThread: destroy a video decoder thread
Michel Kaempf's avatar
Michel Kaempf committed
101
 *******************************************************************************
102
 * Destroy and terminate thread. This function will return 0 if the thread could
Michel Kaempf's avatar
Michel Kaempf committed
103 104 105
 * be destroyed, and non 0 else. The last case probably means that the thread
 * was still active, and another try may succeed.
 *******************************************************************************/
106
void vdec_DestroyThread( vdec_thread_t *p_vdec /*, int *pi_status */ )
Michel Kaempf's avatar
Michel Kaempf committed
107
{
108 109 110 111 112
    intf_DbgMsg("vdec debug: requesting termination of video decoder thread %p\n", p_vdec);

    /* Ask thread to kill itself */
    p_vdec->b_die = 1;

Michel Kaempf's avatar
Michel Kaempf committed
113
    /* Waiting for the decoder thread to exit */
114
    /* Remove this as soon as the "status" flag is implemented */
115
    vlc_thread_join( p_vdec->thread_id );
Michel Kaempf's avatar
Michel Kaempf committed
116 117 118 119 120
}

/* following functions are local */

/*******************************************************************************
121
 * InitThread: initialize video decoder thread
Michel Kaempf's avatar
Michel Kaempf committed
122 123 124 125 126 127 128
 *******************************************************************************
 * 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.
 *******************************************************************************/
static int InitThread( vdec_thread_t *p_vdec )
{
129 130
    intf_DbgMsg("vdec debug: initializing video decoder thread %p\n", p_vdec);

Michel Kaempf's avatar
Michel Kaempf committed
131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146
    /* Initialize other properties */
#ifdef STATS
    p_vdec->c_loops = 0;    
    p_vdec->c_idle_loops = 0;
    p_vdec->c_decoded_pictures = 0;
    p_vdec->c_decoded_i_pictures = 0;
    p_vdec->c_decoded_p_pictures = 0;
    p_vdec->c_decoded_b_pictures = 0;
#endif

    /* Mark thread as running and return */
    intf_DbgMsg("vdec debug: InitThread(%p) succeeded\n", p_vdec);    
    return( 0 );    
}

/*******************************************************************************
147
 * RunThread: video decoder thread
Michel Kaempf's avatar
Michel Kaempf committed
148
 *******************************************************************************
149
 * Video decoder thread. This function does only return when the thread is
Michel Kaempf's avatar
Michel Kaempf committed
150 151 152 153
 * terminated. 
 *******************************************************************************/
static void RunThread( vdec_thread_t *p_vdec )
{
154 155
    intf_DbgMsg("vdec debug: running video decoder thread (%p) (pid == %i)\n",
                p_vdec, getpid());
156

Michel Kaempf's avatar
Michel Kaempf committed
157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
    /* 
     * Initialize thread and free configuration 
     */
    p_vdec->b_error = InitThread( p_vdec );
    if( p_vdec->b_error )
    {
        return;
    }
    p_vdec->b_run = 1;

    /*
     * Main loop - it is not executed if an error occured during
     * initialization
     */
    while( (!p_vdec->b_die) && (!p_vdec->b_error) )
    {
173
        macroblock_t *          p_mb;
174
        
175
        if( (p_mb = vpar_GetMacroblock( &p_vdec->p_vpar->vfifo )) != NULL )
176
        {
177
            DecodeMacroblock( p_vdec, p_mb );
178
        }
Michel Kaempf's avatar
Michel Kaempf committed
179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202
    } 

    /*
     * Error loop
     */
    if( p_vdec->b_error )
    {
        ErrorThread( p_vdec );        
    }

    /* End of thread */
    EndThread( p_vdec );
    p_vdec->b_run = 0;
}

/*******************************************************************************
 * ErrorThread: RunThread() error loop
 *******************************************************************************
 * 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.
 *******************************************************************************/
static void ErrorThread( vdec_thread_t *p_vdec )
{
203
    macroblock_t *       p_mb;
204

Michel Kaempf's avatar
Michel Kaempf committed
205 206 207
    /* Wait until a `die' order */
    while( !p_vdec->b_die )
    {
208 209
        p_mb = vpar_GetMacroblock( &p_vdec->p_vpar->vfifo );
        vpar_DestroyMacroblock( &p_vdec->p_vpar->vfifo, p_mb );
210

Michel Kaempf's avatar
Michel Kaempf committed
211 212 213 214 215 216 217 218 219 220 221 222 223
        /* Sleep a while */
        msleep( VDEC_IDLE_SLEEP );                
    }
}

/*******************************************************************************
 * EndThread: thread destruction
 *******************************************************************************
 * This function is called when the thread ends after a sucessfull 
 * initialization.
 *******************************************************************************/
static void EndThread( vdec_thread_t *p_vdec )
{
224 225
    intf_DbgMsg("vdec debug: EndThread(%p)\n", p_vdec);
}
226

227
/*******************************************************************************
228
 * DecodeMacroblock : decode a macroblock of a picture
229
 *******************************************************************************/
230
static void DecodeMacroblock( vdec_thread_t *p_vdec, macroblock_t * p_mb )
231
{
232
    int             i_b;
Michel Kaempf's avatar
Michel Kaempf committed
233

234 235 236 237
    /*
     * Motion Compensation (ISO/IEC 13818-2 section 7.6)
     */
    (*p_mb->pf_motion)( p_mb );
238

239 240
    /* luminance */
    for( i_b = 0; i_b < 4; i_b++ )
241 242 243 244
    {
        /*
         * Inverse DCT (ISO/IEC 13818-2 section Annex A)
         */
245 246
        (p_mb->pf_idct[i_b])( p_vdec, p_mb->ppi_blocks[i_b],
                              p_mb->pi_sparse_pos[i_b] );
247 248 249 250

        /*
         * Adding prediction and coefficient data (ISO/IEC 13818-2 section 7.6.8)
         */
251
        (p_mb->pf_addb[i_b])( p_mb->ppi_blocks[i_b],
252
                               p_mb->p_data[i_b], p_mb->i_l_stride );
253
    }
254

255 256 257
    /* chrominance */
    for( i_b = 4; i_b < 4 + 2*p_mb->i_chroma_nb_blocks; i_b++ )
    {
258
        /*
259
         * Inverse DCT (ISO/IEC 13818-2 section Annex A)
260
         */
261 262
        (p_mb->pf_idct[i_b])( p_vdec, p_mb->ppi_blocks[i_b],
                              p_mb->pi_sparse_pos[i_b] );
263

264 265 266
        /*
         * Adding prediction and coefficient data (ISO/IEC 13818-2 section 7.6.8)
         */
267
        (p_mb->pf_addb[i_b])( p_mb->ppi_blocks[i_b],
268
                               p_mb->p_data[i_b], p_mb->i_c_stride );
269 270 271
    }

    /*
272 273
     * Decoding is finished, release the macroblock and free
     * unneeded memory.
274
     */
275
    vpar_ReleaseMacroblock( &p_vdec->p_vpar->vfifo, p_mb );
276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326
}

/*******************************************************************************
 * vdec_AddBlock : add a block
 *******************************************************************************/
void vdec_AddBlock( elem_t * p_block, data_t * p_data, int i_incr )
{
    int i_x, i_y;
    
    for( i_y = 0; i_y < 8; i_y++ )
    {
        for( i_x = 0; i_x < 8; i_x++ )
        {
            /* ??? Need clip to be MPEG-2 compliant */
            *p_data++ += *p_block++;
        }
        p_data += i_incr;
    }
}

/*******************************************************************************
 * vdec_CopyBlock : copy a block
 *******************************************************************************/
void vdec_CopyBlock( elem_t * p_block, data_t * p_data, int i_incr )
{
    int i_x, i_y;
    
    for( i_y = 0; i_y < 8; i_y++ )
    {
#ifndef VDEC_DFT
        /* elem_t and data_t are the same */
        memcopy( p_data, p_block, 8*sizeof(data_t) );
        p_data += i_incr+8;
        p_block += 8;
#else
        for( i_x = 0; i_x < 8; i_x++ )
        {
            /* ??? Need clip to be MPEG-2 compliant */
            /* ??? Why does the reference decoder add 128 ??? */
            *p_data++ = *p_block++;
        }
        p_data += i_incr;
#endif
    }
}

/*******************************************************************************
 * vdec_DummyBlock : dummy function that does nothing
 *******************************************************************************/
void vdec_DummyBlock( elem_t * p_block, data_t * p_data, int i_incr )
{
Michel Kaempf's avatar
Michel Kaempf committed
327
}