]> git.sesse.net Git - vlc/blob - src/spu_decoder/spu_decoder.c
(previous commit foired)
[vlc] / src / spu_decoder / spu_decoder.c
1 /*****************************************************************************
2  * spu_decoder.c : spu decoder thread
3  *****************************************************************************
4  * Copyright (C) 2000 VideoLAN
5  *
6  * Authors:
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  * 
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
21  *****************************************************************************/
22
23 /*****************************************************************************
24  * Preamble
25  *****************************************************************************/
26 #include "defs.h"
27
28 #include <stdlib.h>                                      /* malloc(), free() */
29 #include <sys/types.h>                        /* on BSD, uio.h needs types.h */
30 #include <sys/uio.h>                                          /* for input.h */
31 #include <unistd.h>                                              /* getpid() */
32
33 #include "config.h"
34 #include "common.h"
35 #include "threads.h"
36 #include "mtime.h"
37 #include "plugins.h"
38
39 #include "intf_msg.h"
40 #include "debug.h"                                                 /* ASSERT */
41
42 #include "stream_control.h"
43 #include "input_ext-dec.h"
44
45 #include "video.h"
46 #include "video_output.h"
47
48 #include "spu_decoder.h"
49
50 /*
51  * Local prototypes
52  */
53 static int      InitThread          ( spudec_thread_t *p_spudec );
54 static void     RunThread           ( spudec_thread_t *p_spudec );
55 static void     ErrorThread         ( spudec_thread_t *p_spudec );
56 static void     EndThread           ( spudec_thread_t *p_spudec );
57
58 /*****************************************************************************
59  * spudec_CreateThread: create a spu decoder thread
60  *****************************************************************************/
61 vlc_thread_t spudec_CreateThread( vdec_config_t * p_config )
62 {
63     spudec_thread_t *     p_spudec;
64
65     intf_DbgMsg("spudec debug: creating spu decoder thread");
66
67     /* Allocate the memory needed to store the thread's structure */
68     if ( (p_spudec = (spudec_thread_t *)malloc( sizeof(spudec_thread_t) )) == NULL )
69     {
70         intf_ErrMsg("spudec error: not enough memory for spudec_CreateThread() to create the new thread");
71         return( 0 );
72     }
73
74     /*
75      * Initialize the thread properties
76      */
77     p_spudec->p_fifo->b_die = 0;
78     p_spudec->p_fifo->b_error = 0;
79     p_spudec->p_config = p_config;
80     p_spudec->p_fifo = p_config->decoder_config.p_decoder_fifo;
81
82     /* Get the video output informations */
83     p_spudec->p_vout = p_config->p_vout;
84
85     /* Spawn the spu decoder thread */
86     if ( vlc_thread_create(&p_spudec->thread_id, "spu decoder",
87          (vlc_thread_func_t)RunThread, (void *)p_spudec) )
88     {
89         intf_ErrMsg("spudec error: can't spawn spu decoder thread");
90         free( p_spudec );
91         return( 0 );
92     }
93
94     intf_DbgMsg("spudec debug: spu decoder thread (%p) created", p_spudec);
95     return( p_spudec->thread_id );
96 }
97
98 /* following functions are local */
99
100 /*****************************************************************************
101  * InitThread: initialize spu decoder thread
102  *****************************************************************************
103  * This function is called from RunThread and performs the second step of the
104  * initialization. It returns 0 on success. Note that the thread's flag are not
105  * modified inside this function.
106  *****************************************************************************/
107 static int InitThread( spudec_thread_t *p_spudec )
108 {
109     intf_DbgMsg("spudec debug: initializing spu decoder thread %p", p_spudec);
110
111     p_spudec->p_config->decoder_config.pf_init_bit_stream( &p_spudec->bit_stream,
112             p_spudec->p_config->decoder_config.p_decoder_fifo );
113
114     /* Mark thread as running and return */
115     intf_DbgMsg( "spudec debug: InitThread(%p) succeeded", p_spudec );
116     return( 0 );
117 }
118
119 /*****************************************************************************
120  * RunThread: spu decoder thread
121  *****************************************************************************
122  * spu decoder thread. This function only returns when the thread is
123  * terminated.
124  *****************************************************************************/
125 static void RunThread( spudec_thread_t *p_spudec )
126 {
127     intf_DbgMsg("spudec debug: running spu decoder thread (%p) (pid == %i)",
128         p_spudec, getpid());
129
130     /*
131      * Initialize thread and free configuration
132      */
133     p_spudec->p_fifo->b_error = InitThread( p_spudec );
134
135     /*
136      * Main loop - it is not executed if an error occured during
137      * initialization
138      */
139     while( (!p_spudec->p_fifo->b_die) && (!p_spudec->p_fifo->b_error) )
140     {
141         int i_packet_size;
142         int i_rle_size;
143         int i_index, i_next;
144         boolean_t b_valid;
145         subpicture_t * p_spu = NULL;
146
147         while( !DECODER_FIFO_ISEMPTY(*p_spudec->p_fifo) )
148         {
149             /* wait for the next SPU ID.
150              * XXX: We trash 0xff bytes since they probably come from
151              * an incomplete previous packet */
152             do
153             {
154                 i_packet_size = GetByte( &p_spudec->bit_stream );
155             }
156             while( i_packet_size == 0xff );
157
158             if( p_spudec->p_fifo->b_die )
159             {
160                 goto bad_packet;
161             }
162
163             /* the total size - should equal the sum of the
164              * PES packet size that form the SPU packet */
165             i_packet_size = i_packet_size << 8
166                              | GetByte( &p_spudec->bit_stream );
167
168             /* the RLE stuff size */
169             i_rle_size = GetByte( &p_spudec->bit_stream ) << 8
170                           | GetByte( &p_spudec->bit_stream );
171
172             /* if the values we got aren't too strange, decode the data */
173             if( i_rle_size < i_packet_size )
174             {
175                 /* allocate the subpicture.
176                  * FIXME: we should check if the allocation failed */
177                 p_spu = vout_CreateSubPicture( p_spudec->p_vout,
178                                                DVD_SUBPICTURE, i_rle_size );
179                 /* get display time */
180                 p_spu->begin_date = p_spu->end_date
181                                 = DECODER_FIFO_START(*p_spudec->p_fifo)->i_pts;
182
183                 /* get RLE data, skip 4 bytes for the first two read offsets */
184                 GetChunk( &p_spudec->bit_stream, p_spu->p_data,
185                           i_rle_size - 4 );
186
187                 if( p_spudec->p_fifo->b_die )
188                 {
189                     goto bad_packet;
190                 }
191
192                 /* continue parsing after the RLE part */
193                 i_index = i_rle_size;
194
195                 /* assume packet is valid */
196                 b_valid = 1;
197
198                 /* getting the control part */
199                 do
200                 {
201                     unsigned char i_cmd;
202                     unsigned int i_word, i_date;
203
204                     /* Get the sequence date */
205                     i_date = GetByte( &p_spudec->bit_stream ) << 8
206                               | GetByte( &p_spudec->bit_stream );
207
208                     /* Next offset */
209                     i_next = GetByte( &p_spudec->bit_stream ) << 8
210                               | GetByte( &p_spudec->bit_stream );
211
212                     i_index += 4;
213
214                     do
215                     {
216                         i_cmd = GetByte( &p_spudec->bit_stream );
217                         i_index++;
218
219                         switch( i_cmd )
220                         {
221                             case SPU_CMD_FORCE_DISPLAY:
222                                 /* 00 (force displaying) */
223                                 break;
224                             /* FIXME: here we have to calculate dates. It's
225                              * around i_date * 12000 but I don't know
226                              * how much exactly.
227                              */
228                             case SPU_CMD_START_DISPLAY:
229                                 /* 01 (start displaying) */
230                                 p_spu->begin_date += ( i_date * 12000 );
231                                 break;
232                             case SPU_CMD_STOP_DISPLAY:
233                                 /* 02 (stop displaying) */
234                                 p_spu->end_date += ( i_date * 12000 );
235                                 break;
236                             case SPU_CMD_SET_PALETTE:
237                                 /* 03xxxx (palette) */
238                                 i_word = GetByte( &p_spudec->bit_stream ) << 8
239                                           | GetByte( &p_spudec->bit_stream );
240                                 i_index += 2;
241                                 break;
242                             case SPU_CMD_SET_ALPHACHANNEL:
243                                 /* 04xxxx (alpha channel) */
244                                 i_word = GetByte( &p_spudec->bit_stream ) << 8
245                                           | GetByte( &p_spudec->bit_stream );
246                                 i_index += 2;
247                                 break;
248                             case SPU_CMD_SET_COORDINATES:
249                                 /* 05xxxyyyxxxyyy (coordinates) */
250                                 i_word = GetByte( &p_spudec->bit_stream );
251                                 p_spu->i_x = (i_word << 4)
252                                     | GetBits( &p_spudec->bit_stream, 4 );
253
254                                 i_word = GetBits( &p_spudec->bit_stream, 4 );
255                                 p_spu->i_width = p_spu->i_x - ( (i_word << 8)
256                                     | GetBits( &p_spudec->bit_stream, 8 ) ) + 1;
257
258                                 i_word = GetBits( &p_spudec->bit_stream, 8 );
259                                 p_spu->i_y = (i_word << 4)
260                                     | GetBits( &p_spudec->bit_stream, 4 );
261
262                                 i_word = GetBits( &p_spudec->bit_stream, 4 );
263                                 p_spu->i_height = p_spu->i_y - ( (i_word << 8)
264                                     | GetByte( &p_spudec->bit_stream ) ) + 1;
265
266                                 i_index += 6;
267                                 break;
268                             case SPU_CMD_SET_OFFSETS:
269                                 /* 06xxxxyyyy (byte offsets) */
270                                 p_spu->type.spu.i_offset[0] =
271                                     ( GetByte( &p_spudec->bit_stream ) << 8
272                                       | GetByte( &p_spudec->bit_stream ) ) - 4;
273                                 p_spu->type.spu.i_offset[1] =
274                                     ( GetByte( &p_spudec->bit_stream ) << 8
275                                       | GetByte( &p_spudec->bit_stream ) ) - 4;
276                                 i_index += 4;
277                                 break;
278                             case SPU_CMD_END:
279                                 /* ff (end) */
280                                 break;
281                             default:
282                                 /* ?? (unknown command) */
283                                 intf_ErrMsg( "spudec: unknown command 0x%.2x",
284                                              i_cmd );
285                                 b_valid = 0;
286                                 break;
287                         }
288                     }
289                     while( b_valid && ( i_cmd != SPU_CMD_END ) );
290                 }
291                 while( b_valid && ( i_index == i_next ) );
292
293                 if( b_valid )
294                 {
295                     /* SPU is finished - we can tell the video output
296                      * to display it */
297                     vout_DisplaySubPicture( p_spudec->p_vout, p_spu );
298                 }
299                 else
300                 {
301                     vout_DestroySubPicture( p_spudec->p_vout, p_spu );
302                 }
303             }
304             else 
305             {
306                 /* Unexpected PES packet - trash it */
307                 intf_ErrMsg( "spudec: trying to recover from bad packet" );
308                 vlc_mutex_lock( &p_spudec->p_fifo->data_lock );
309                 p_spudec->p_fifo->pf_delete_pes( p_spudec->p_fifo->p_packets_mgt,
310                                       DECODER_FIFO_START(*p_spudec->p_fifo) );
311                 DECODER_FIFO_INCSTART( *p_spudec->p_fifo );
312                 vlc_mutex_unlock( &p_spudec->p_fifo->data_lock );
313             }
314 bad_packet:
315         }
316     }
317
318     /*
319      * Error loop
320      */
321     if( p_spudec->p_fifo->b_error )
322     {
323         ErrorThread( p_spudec );
324     }
325
326     /* End of thread */
327     EndThread( p_spudec );
328 }
329
330 /*****************************************************************************
331  * ErrorThread: RunThread() error loop
332  *****************************************************************************
333  * This function is called when an error occured during thread main's loop. The
334  * thread can still receive feed, but must be ready to terminate as soon as
335  * possible.
336  *****************************************************************************/
337 static void ErrorThread( spudec_thread_t *p_spudec )
338 {
339     /* We take the lock, because we are going to read/write the start/end
340      * indexes of the decoder fifo */
341     vlc_mutex_lock( &p_spudec->p_fifo->data_lock );
342
343     /* Wait until a `die' order is sent */
344     while( !p_spudec->p_fifo->b_die )
345     {
346         /* Trash all received PES packets */
347         while( !DECODER_FIFO_ISEMPTY(*p_spudec->p_fifo) )
348         {
349             p_spudec->p_fifo->pf_delete_pes( p_spudec->p_fifo->p_packets_mgt,
350                     DECODER_FIFO_START(*p_spudec->p_fifo) );
351             DECODER_FIFO_INCSTART( *p_spudec->p_fifo );
352         }
353
354         /* Waiting for the input thread to put new PES packets in the fifo */
355         vlc_cond_wait( &p_spudec->p_fifo->data_wait, &p_spudec->p_fifo->data_lock );
356     }
357
358     /* We can release the lock before leaving */
359     vlc_mutex_unlock( &p_spudec->p_fifo->data_lock );
360 }
361
362 /*****************************************************************************
363  * EndThread: thread destruction
364  *****************************************************************************
365  * This function is called when the thread ends after a sucessful
366  * initialization.
367  *****************************************************************************/
368 static void EndThread( spudec_thread_t *p_spudec )
369 {
370     intf_DbgMsg( "spudec debug: destroying spu decoder thread %p", p_spudec );
371     free( p_spudec->p_config );
372     free( p_spudec );
373     intf_DbgMsg( "spudec debug: spu decoder thread %p destroyed", p_spudec);
374 }
375