spu_decoder.c 14.3 KB
Newer Older
1
/*****************************************************************************
2
 * spu_decoder.c : spu decoder thread
3 4 5 6 7 8 9 10 11
 *****************************************************************************
 * Copyright (C) 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

/* repomp sur video_decoder.c
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 <sys/types.h>                        /* on BSD, uio.h needs types.h */
#include <sys/uio.h>                                          /* for input.h */
#include <unistd.h>                                              /* getpid() */
35 36 37

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

#include "intf_msg.h"
43
#include "debug.h"                                                 /* ASSERT */
44

45 46
#include "stream_control.h"
#include "input_ext-dec.h"
47

48 49 50
#include "video.h"
#include "video_output.h"

51 52 53 54 55 56 57 58 59 60
#include "spu_decoder.h"

/*
 * Local prototypes
 */
static int      InitThread          ( spudec_thread_t *p_spudec );
static void     RunThread           ( spudec_thread_t *p_spudec );
static void     ErrorThread         ( spudec_thread_t *p_spudec );
static void     EndThread           ( spudec_thread_t *p_spudec );

61 62 63 64 65
#define GetWord( i ) \
    i  = GetByte( &p_spudec->bit_stream ) << 8; \
    i += GetByte( &p_spudec->bit_stream ); \
    i_index += 2;

66
/*****************************************************************************
67
 * spudec_CreateThread: create a spu decoder thread
68
 *****************************************************************************/
69
vlc_thread_t spudec_CreateThread( vdec_config_t * p_config )
70 71 72 73 74 75 76 77 78
{
    spudec_thread_t *     p_spudec;

    intf_DbgMsg("spudec debug: creating spu decoder thread\n");

    /* Allocate the memory needed to store the thread's structure */
    if ( (p_spudec = (spudec_thread_t *)malloc( sizeof(spudec_thread_t) )) == NULL )
    {
        intf_ErrMsg("spudec error: not enough memory for spudec_CreateThread() to create the new thread\n");
79
        return( 0 );
80 81 82 83 84
    }

    /*
     * Initialize the thread properties
     */
85 86
    p_spudec->p_fifo->b_die = 0;
    p_spudec->p_fifo->b_error = 0;
87 88
    p_spudec->p_config = p_config;
    p_spudec->p_fifo = p_config->decoder_config.p_decoder_fifo;
89

90
    /* Get the video output informations */
91
    p_spudec->p_vout = p_config->p_vout;
92

93 94 95 96 97 98
    /* Spawn the spu decoder thread */
    if ( vlc_thread_create(&p_spudec->thread_id, "spu decoder",
         (vlc_thread_func_t)RunThread, (void *)p_spudec) )
    {
        intf_ErrMsg("spudec error: can't spawn spu decoder thread\n");
        free( p_spudec );
99
        return( 0 );
100 101 102
    }

    intf_DbgMsg("spudec debug: spu decoder thread (%p) created\n", p_spudec);
103
    return( p_spudec->thread_id );
104 105 106 107
}

/* following functions are local */

108
/*****************************************************************************
109
 * InitThread: initialize spu decoder thread
110
 *****************************************************************************
111 112 113
 * 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.
114
 *****************************************************************************/
115 116 117 118
static int InitThread( spudec_thread_t *p_spudec )
{
    intf_DbgMsg("spudec debug: initializing spu decoder thread %p\n", p_spudec);

119 120
    p_spudec->p_config->decoder_config.pf_init_bit_stream( &p_spudec->bit_stream,
            p_spudec->p_config->decoder_config.p_decoder_fifo );
Michel Kaempf's avatar
Michel Kaempf committed
121

122
    /* Mark thread as running and return */
Michel Kaempf's avatar
Michel Kaempf committed
123 124
    intf_DbgMsg( "spudec debug: InitThread(%p) succeeded\n", p_spudec );
    return( 0 );
125 126
}

127
/*****************************************************************************
128
 * RunThread: spu decoder thread
129
 *****************************************************************************
130
 * spu decoder thread. This function only returns when the thread is
131 132
 * terminated.
 *****************************************************************************/
133 134 135
static void RunThread( spudec_thread_t *p_spudec )
{
    intf_DbgMsg("spudec debug: running spu decoder thread (%p) (pid == %i)\n",
Michel Kaempf's avatar
Michel Kaempf committed
136
        p_spudec, getpid());
137

Michel Kaempf's avatar
Michel Kaempf committed
138 139
    /*
     * Initialize thread and free configuration
140
     */
141
    p_spudec->p_fifo->b_error = InitThread( p_spudec );
142 143 144 145 146

    /*
     * Main loop - it is not executed if an error occured during
     * initialization
     */
147
    while( (!p_spudec->p_fifo->b_die) && (!p_spudec->p_fifo->b_error) )
148
    {
149 150 151
        int i_packet_size;
        int i_rle_size;
        int i_index;
Sam Hocevar's avatar
NEWS:  
Sam Hocevar committed
152 153 154
        int i_pes_size;
        int i_pes_count;
        boolean_t       b_finished;
155
        unsigned char * p_spu_data;
Sam Hocevar's avatar
NEWS:  
Sam Hocevar committed
156
        subpicture_t  * p_spu = NULL;
157

158
        while( !DECODER_FIFO_ISEMPTY(*p_spudec->p_fifo) )
Michel Kaempf's avatar
Michel Kaempf committed
159
        {
Sam Hocevar's avatar
NEWS:  
Sam Hocevar committed
160
            /* wait for the next SPU ID.
161
             * XXX: We trash 0xff bytes since they probably come from
Sam Hocevar's avatar
NEWS:  
Sam Hocevar committed
162
             * an incomplete previous packet */
163 164
            do
            {
Sam Hocevar's avatar
NEWS:  
Sam Hocevar committed
165
                i_packet_size = GetByte( &p_spudec->bit_stream );
166
            }
Sam Hocevar's avatar
NEWS:  
Sam Hocevar committed
167
            while( i_packet_size == 0xff );
168

169
            if( p_spudec->p_fifo->b_die )
Sam Hocevar's avatar
Sam Hocevar committed
170 171
                break;

Sam Hocevar's avatar
NEWS:  
Sam Hocevar committed
172 173 174 175 176
            /* the total size - should equal the sum of the
             * PES packet size that form the SPU packet */
            i_packet_size = ( i_packet_size << 8 )
                            + GetByte( &p_spudec->bit_stream );
            i_index = 2;
177

Sam Hocevar's avatar
NEWS:  
Sam Hocevar committed
178
            /* get the useful PES size (real size - 10) */
179
            i_pes_size = DECODER_FIFO_START(*p_spudec->p_fifo)->i_pes_size - 9;
Sam Hocevar's avatar
NEWS:  
Sam Hocevar committed
180
            i_pes_count = 1;
181

Sam Hocevar's avatar
NEWS:  
Sam Hocevar committed
182
            /* the RLE stuff size */
183 184
            GetWord( i_rle_size );

Sam Hocevar's avatar
NEWS:  
Sam Hocevar committed
185 186 187 188 189 190
            /* if the values we got aren't too strange, decode the data */
            if( i_rle_size < i_packet_size )
            {
                /* allocate the subpicture.
                 * FIXME: we should check if the allocation failed */
                p_spu = vout_CreateSubPicture( p_spudec->p_vout,
191
                                           DVD_SUBPICTURE, i_rle_size );
Sam Hocevar's avatar
NEWS:  
Sam Hocevar committed
192
                p_spu_data = p_spu->p_data;
193

194 195
                /* get display time */
                p_spu->begin_date = p_spu->end_date
196
                                = DECODER_FIFO_START(*p_spudec->p_fifo)->i_pts;
197

Sam Hocevar's avatar
NEWS:  
Sam Hocevar committed
198 199
                /* getting the RLE part */
                while( i_index++ < i_rle_size )
200
                {
Sam Hocevar's avatar
NEWS:  
Sam Hocevar committed
201
                    /* skip the leading byte of a PES */
202
                    /* FIXME: this part definitely looks strange */
Sam Hocevar's avatar
NEWS:  
Sam Hocevar committed
203 204 205 206 207
                    if ( !((i_index + 3) % i_pes_size) )
                    {
                        i_pes_count++;
                    }
                    *p_spu_data++ = GetByte( &p_spudec->bit_stream );
208 209
                }

Sam Hocevar's avatar
NEWS:  
Sam Hocevar committed
210 211 212
                /* getting the control part */
                b_finished = 0;
                do
213 214 215
                {
                    unsigned char i_cmd;
                    unsigned int i_word;
216
                    unsigned int i_date;
217

Sam Hocevar's avatar
NEWS:  
Sam Hocevar committed
218
                    /* the date */
219
                    GetWord( i_date );
220

Sam Hocevar's avatar
NEWS:  
Sam Hocevar committed
221
                    /* next offset, no next offset if == i_index-5 */
222
                    GetWord( i_word );
Sam Hocevar's avatar
NEWS:  
Sam Hocevar committed
223
                    b_finished = ( i_index - 5 >= i_word );
224

Sam Hocevar's avatar
NEWS:  
Sam Hocevar committed
225 226
                    do
                    {
227
                        i_cmd = GetByte( &p_spudec->bit_stream );
Sam Hocevar's avatar
NEWS:  
Sam Hocevar committed
228
                        i_index++;
229

Sam Hocevar's avatar
NEWS:  
Sam Hocevar committed
230 231
                        switch( i_cmd )
                        {
232
                            case SPU_CMD_FORCE_DISPLAY:
233
                                /* 00 (force displaying) */
234
                                break;
Sam Hocevar's avatar
Sam Hocevar committed
235
                            /* FIXME: here we have to calculate dates. It's
236
                             * around i_date * 12000 but I don't know
237
                             * how much exactly.
Sam Hocevar's avatar
Sam Hocevar committed
238
                             */
239
                            case SPU_CMD_START_DISPLAY:
Sam Hocevar's avatar
NEWS:  
Sam Hocevar committed
240
                                /* 01 (start displaying) */
241
                                p_spu->begin_date += ( i_date * 12000 );
Sam Hocevar's avatar
Sam Hocevar committed
242
                                break;
243
                            case SPU_CMD_STOP_DISPLAY:
Sam Hocevar's avatar
NEWS:  
Sam Hocevar committed
244
                                /* 02 (stop displaying) */
245
                                p_spu->end_date += ( i_date * 12000 );
Sam Hocevar's avatar
Sam Hocevar committed
246
                                break;
247
                            case SPU_CMD_SET_PALETTE:
Sam Hocevar's avatar
NEWS:  
Sam Hocevar committed
248 249
                                /* 03xxxx (palette) */
                                GetWord( i_word );
250
                                break;
251
                            case SPU_CMD_SET_ALPHACHANNEL:
Sam Hocevar's avatar
NEWS:  
Sam Hocevar committed
252 253
                                /* 04xxxx (alpha channel) */
                                GetWord( i_word );
254
                                break;
255
                            case SPU_CMD_SET_COORDINATES:
Sam Hocevar's avatar
NEWS:  
Sam Hocevar committed
256
                                /* 05xxxyyyxxxyyy (coordinates) */
257
                                i_word = GetByte( &p_spudec->bit_stream );
Sam Hocevar's avatar
Sam Hocevar committed
258 259
                                p_spu->i_x = (i_word << 4)
                                    | GetBits( &p_spudec->bit_stream, 4 );
260

261
                                i_word = GetBits( &p_spudec->bit_stream, 4 );
Sam Hocevar's avatar
Sam Hocevar committed
262 263
                                p_spu->i_width = p_spu->i_x - ( (i_word << 8)
                                    | GetByte( &p_spudec->bit_stream ) ) + 1;
264

265
                                i_word = GetByte( &p_spudec->bit_stream );
Sam Hocevar's avatar
Sam Hocevar committed
266 267
                                p_spu->i_y = (i_word << 4)
                                    | GetBits( &p_spudec->bit_stream, 4 );
268

269
                                i_word = GetBits( &p_spudec->bit_stream, 4 );
Sam Hocevar's avatar
Sam Hocevar committed
270 271
                                p_spu->i_height = p_spu->i_y - ( (i_word << 8)
                                    | GetByte( &p_spudec->bit_stream ) ) + 1;
272

273
				i_index += 6;
274
                                break;
275
                            case SPU_CMD_SET_OFFSETS:
Sam Hocevar's avatar
NEWS:  
Sam Hocevar committed
276 277 278 279 280
                                /* 06xxxxyyyy (byte offsets) */
                                GetWord( i_word );
                                p_spu->type.spu.i_offset[0] = i_word - 4;
                                GetWord( i_word );
                                p_spu->type.spu.i_offset[1] = i_word - 4;
281
                                break;
282
                            case SPU_CMD_END:
Sam Hocevar's avatar
NEWS:  
Sam Hocevar committed
283
                                /* ff (end) */
284
                                break;
Sam Hocevar's avatar
NEWS:  
Sam Hocevar committed
285 286
                            default:
                                /* ?? (unknown command) */
287 288
                                intf_ErrMsg( "spudec: unknown command 0x%.2x\n",
                                             i_cmd );
289
                                break;
Sam Hocevar's avatar
NEWS:  
Sam Hocevar committed
290 291
                        }
                    }
292
                    while( i_cmd != SPU_CMD_END );
Sam Hocevar's avatar
NEWS:  
Sam Hocevar committed
293 294
                }
                while( !b_finished );
295

296 297
                /* SPU is finished - we can tell the video output
                 * to display it */
Sam Hocevar's avatar
NEWS:  
Sam Hocevar committed
298
                vout_DisplaySubPicture( p_spudec->p_vout, p_spu );
299 300 301
            }
            else 
            {
Sam Hocevar's avatar
NEWS:  
Sam Hocevar committed
302
                /* Unexpected PES packet - trash it */
Sam Hocevar's avatar
Sam Hocevar committed
303
                intf_ErrMsg( "spudec: trying to recover from bad packet\n" );
304 305 306 307 308
                vlc_mutex_lock( &p_spudec->p_fifo->data_lock );
                p_spudec->p_fifo->pf_delete_pes( p_spudec->p_fifo->p_packets_mgt,
                                      DECODER_FIFO_START(*p_spudec->p_fifo) );
                DECODER_FIFO_INCSTART( *p_spudec->p_fifo );
                vlc_mutex_unlock( &p_spudec->p_fifo->data_lock );
309 310
            }

Michel Kaempf's avatar
Michel Kaempf committed
311 312
        }
    }
313 314 315 316

    /*
     * Error loop
     */
317
    if( p_spudec->p_fifo->b_error )
318
    {
Michel Kaempf's avatar
Michel Kaempf committed
319
        ErrorThread( p_spudec );
320 321 322 323 324 325
    }

    /* End of thread */
    EndThread( p_spudec );
}

326
/*****************************************************************************
327
 * ErrorThread: RunThread() error loop
328
 *****************************************************************************
329 330 331
 * 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.
332
 *****************************************************************************/
333 334
static void ErrorThread( spudec_thread_t *p_spudec )
{
Michel Kaempf's avatar
Michel Kaempf committed
335 336
    /* We take the lock, because we are going to read/write the start/end
     * indexes of the decoder fifo */
337
    vlc_mutex_lock( &p_spudec->p_fifo->data_lock );
Michel Kaempf's avatar
Michel Kaempf committed
338 339

    /* Wait until a `die' order is sent */
340
    while( !p_spudec->p_fifo->b_die )
341
    {
Michel Kaempf's avatar
Michel Kaempf committed
342
        /* Trash all received PES packets */
343
        while( !DECODER_FIFO_ISEMPTY(*p_spudec->p_fifo) )
Michel Kaempf's avatar
Michel Kaempf committed
344
        {
345 346 347
            p_spudec->p_fifo->pf_delete_pes( p_spudec->p_fifo->p_packets_mgt,
                    DECODER_FIFO_START(*p_spudec->p_fifo) );
            DECODER_FIFO_INCSTART( *p_spudec->p_fifo );
Michel Kaempf's avatar
Michel Kaempf committed
348 349 350
        }

        /* Waiting for the input thread to put new PES packets in the fifo */
351
        vlc_cond_wait( &p_spudec->p_fifo->data_wait, &p_spudec->p_fifo->data_lock );
352
    }
Michel Kaempf's avatar
Michel Kaempf committed
353 354

    /* We can release the lock before leaving */
355
    vlc_mutex_unlock( &p_spudec->p_fifo->data_lock );
356 357
}

358
/*****************************************************************************
359
 * EndThread: thread destruction
360
 *****************************************************************************
361
 * This function is called when the thread ends after a sucessful
362
 * initialization.
363
 *****************************************************************************/
364 365
static void EndThread( spudec_thread_t *p_spudec )
{
Michel Kaempf's avatar
Michel Kaempf committed
366 367 368
    intf_DbgMsg( "spudec debug: destroying spu decoder thread %p\n", p_spudec );
    free( p_spudec );
    intf_DbgMsg( "spudec debug: spu decoder thread %p destroyed\n", p_spudec);
369
}
Sam Hocevar's avatar
Sam Hocevar committed
370