]> git.sesse.net Git - vlc/blob - src/spu_decoder/spu_decoder.c
* Fixed a few warnings with gcc 3.0.
[vlc] / src / spu_decoder / spu_decoder.c
1 /*****************************************************************************
2  * spu_decoder.c : spu decoder thread
3  *****************************************************************************
4  * Copyright (C) 2000 VideoLAN
5  * $Id: spu_decoder.c,v 1.40 2001/05/06 04:32:02 sam Exp $
6  *
7  * Authors: Samuel Hocevar <sam@zoy.org>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  * 
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #include "defs.h"
28
29 #include <unistd.h>                                              /* getpid() */
30 #ifdef WIN32                   /* getpid() for win32 is located in process.h */
31 #include <process.h>
32 #endif
33
34 #include <stdlib.h>                                      /* malloc(), free() */
35 #include <string.h>                                    /* memcpy(), memset() */
36
37 #include "config.h"
38 #include "common.h"
39 #include "threads.h"
40 #include "mtime.h"
41
42 #include "intf_msg.h"
43
44 #include "stream_control.h"
45 #include "input_ext-dec.h"
46
47 #include "video.h"
48 #include "video_output.h"
49
50 #include "spu_decoder.h"
51
52 #include "main.h" /* XXX: remove this later */
53
54 /*****************************************************************************
55  * Local prototypes
56  *****************************************************************************/
57 static int  InitThread  ( spudec_thread_t * );
58 static void RunThread   ( spudec_thread_t * );
59 static void ErrorThread ( spudec_thread_t * );
60 static void EndThread   ( spudec_thread_t * );
61
62 static int  SyncPacket           ( spudec_thread_t * );
63 static void ParsePacket          ( spudec_thread_t * );
64 static int  ParseControlSequences( spudec_thread_t *, subpicture_t * );
65 static int  ParseRLE             ( u8 *,              subpicture_t * );
66
67 /*****************************************************************************
68  * spudec_CreateThread: create a spu decoder thread
69  *****************************************************************************/
70 vlc_thread_t spudec_CreateThread( vdec_config_t * p_config )
71 {
72     spudec_thread_t *     p_spudec;
73
74     /* Allocate the memory needed to store the thread's structure */
75     p_spudec = (spudec_thread_t *)malloc( sizeof(spudec_thread_t) );
76
77     if ( p_spudec == NULL )
78     {
79         intf_ErrMsg( "spudec error: not enough memory "
80                      "for spudec_CreateThread() to create the new thread" );
81         return( 0 );
82     }
83
84     /*
85      * Initialize the thread properties
86      */
87     p_spudec->p_config = p_config;
88
89     p_spudec->p_fifo = p_config->decoder_config.p_decoder_fifo;
90
91     /* XXX: The vout request and fifo opening will eventually be here */
92
93     /* Spawn an audio output if there is none */
94     vlc_mutex_lock( &p_vout_bank->lock );
95
96     if( p_vout_bank->i_count == 0 )
97     {
98         intf_Msg( "spudec: no vout present, spawning one" );
99
100         p_spudec->p_vout = vout_CreateThread( NULL );
101
102         /* Everything failed */
103         if( p_spudec->p_vout == NULL )
104         {
105             intf_Msg( "spudec: can't open vout, aborting" );
106             vlc_mutex_unlock( &p_vout_bank->lock );
107             free( p_spudec );
108
109             return 0;
110         }
111
112         p_vout_bank->pp_vout[ p_vout_bank->i_count ] = p_spudec->p_vout;
113         p_vout_bank->i_count++;
114     }
115     else
116     {
117         /* Take the first video output FIXME: take the best one */
118         p_spudec->p_vout = p_vout_bank->pp_vout[ 0 ];
119     }
120
121     vlc_mutex_unlock( &p_vout_bank->lock );
122
123     /* Spawn the spu decoder thread */
124     if ( vlc_thread_create(&p_spudec->thread_id, "spu decoder",
125          (vlc_thread_func_t)RunThread, (void *)p_spudec) )
126     {
127         intf_ErrMsg( "spudec error: can't spawn spu decoder thread" );
128         free( p_spudec );
129         return 0;
130     }
131
132     return( p_spudec->thread_id );
133 }
134
135 /* following functions are local */
136
137 /*****************************************************************************
138  * InitThread: initialize spu decoder thread
139  *****************************************************************************
140  * This function is called from RunThread and performs the second step of the
141  * initialization. It returns 0 on success. Note that the thread's flag are not
142  * modified inside this function.
143  *****************************************************************************/
144 static int InitThread( spudec_thread_t *p_spudec )
145 {
146     p_spudec->p_config->decoder_config.pf_init_bit_stream(
147             &p_spudec->bit_stream,
148             p_spudec->p_config->decoder_config.p_decoder_fifo, NULL, NULL );
149
150     /* Mark thread as running and return */
151     return( 0 );
152 }
153
154 /*****************************************************************************
155  * RunThread: spu decoder thread
156  *****************************************************************************
157  * spu decoder thread. This function only returns when the thread is
158  * terminated.
159  *****************************************************************************/
160 static void RunThread( spudec_thread_t *p_spudec )
161 {
162     intf_WarnMsg( 1, "spudec: spu decoder thread %i spawned", getpid() );
163
164     /*
165      * Initialize thread and free configuration
166      */
167     p_spudec->p_fifo->b_error = InitThread( p_spudec );
168
169     /*
170      * Main loop - it is not executed if an error occured during
171      * initialization
172      */
173     while( (!p_spudec->p_fifo->b_die) && (!p_spudec->p_fifo->b_error) )
174     {
175         if( !SyncPacket( p_spudec ) )
176         {
177             ParsePacket( p_spudec );
178         }
179     }
180
181     /*
182      * Error loop
183      */
184     if( p_spudec->p_fifo->b_error )
185     {
186         ErrorThread( p_spudec );
187     }
188
189     /* End of thread */
190     intf_WarnMsg( 1, "spudec: destroying spu decoder thread %i", getpid() );
191     EndThread( p_spudec );
192 }
193
194 /*****************************************************************************
195  * ErrorThread: RunThread() error loop
196  *****************************************************************************
197  * This function is called when an error occured during thread main's loop. The
198  * thread can still receive feed, but must be ready to terminate as soon as
199  * possible.
200  *****************************************************************************/
201 static void ErrorThread( spudec_thread_t *p_spudec )
202 {
203     /* We take the lock, because we are going to read/write the start/end
204      * indexes of the decoder fifo */
205     vlc_mutex_lock( &p_spudec->p_fifo->data_lock );
206
207     /* Wait until a `die' order is sent */
208     while( !p_spudec->p_fifo->b_die )
209     {
210         /* Trash all received PES packets */
211         while( !DECODER_FIFO_ISEMPTY(*p_spudec->p_fifo) )
212         {
213             p_spudec->p_fifo->pf_delete_pes( p_spudec->p_fifo->p_packets_mgt,
214                     DECODER_FIFO_START(*p_spudec->p_fifo) );
215             DECODER_FIFO_INCSTART( *p_spudec->p_fifo );
216         }
217
218         /* Waiting for the input thread to put new PES packets in the fifo */
219         vlc_cond_wait( &p_spudec->p_fifo->data_wait,
220                        &p_spudec->p_fifo->data_lock );
221     }
222
223     /* We can release the lock before leaving */
224     vlc_mutex_unlock( &p_spudec->p_fifo->data_lock );
225 }
226
227 /*****************************************************************************
228  * EndThread: thread destruction
229  *****************************************************************************
230  * This function is called when the thread ends after a sucessful
231  * initialization.
232  *****************************************************************************/
233 static void EndThread( spudec_thread_t *p_spudec )
234 {
235     free( p_spudec->p_config );
236     free( p_spudec );
237 }
238
239 /*****************************************************************************
240  * SyncPacket: get in sync with the stream
241  *****************************************************************************
242  * This function makes a few sanity checks and returns 0 if it looks like we
243  * are at the beginning of a subpicture packet.
244  *****************************************************************************/
245 static int SyncPacket( spudec_thread_t *p_spudec )
246 {
247     /* Re-align the buffer on an 8-bit boundary */
248     RealignBits( &p_spudec->bit_stream );
249
250     /* The total SPU packet size, often bigger than a PS packet */
251     p_spudec->i_spu_size = GetBits( &p_spudec->bit_stream, 16 );
252
253     /* The RLE stuff size (remove 4 because we just read 32 bits) */
254     p_spudec->i_rle_size = ShowBits( &p_spudec->bit_stream, 16 ) - 4;
255
256     /* If the values we got are a bit strange, skip packet */
257     if( p_spudec->i_rle_size >= p_spudec->i_spu_size )
258     {
259         return( 1 );
260     }
261
262     RemoveBits( &p_spudec->bit_stream, 16 );
263
264     return( 0 );
265 }
266
267 /*****************************************************************************
268  * ParsePacket: parse an SPU packet and send it to the video output
269  *****************************************************************************
270  * This function parses the SPU packet and, if valid, sends it to the
271  * video output.
272  *****************************************************************************/
273 static void ParsePacket( spudec_thread_t *p_spudec )
274 {
275     subpicture_t * p_spu;
276     u8           * p_src;
277
278     /* We cannot display a subpicture with no date */
279     if( DECODER_FIFO_START(*p_spudec->p_fifo)->i_pts == 0 )
280     {
281         return;
282     }
283
284     /* Allocate the subpicture internal data. */
285     p_spu = vout_CreateSubPicture( p_spudec->p_vout, DVD_SUBPICTURE,
286                                    p_spudec->i_rle_size * 4 );
287     /* Rationale for the "p_spudec->i_rle_size * 4": we are going to
288      * expand the RLE stuff so that we won't need to read nibbles later
289      * on. This will speed things up a lot. Plus, we'll only need to do
290      * this stupid interlacing stuff once. */
291
292     if( p_spu == NULL )
293     {
294         return;
295     }
296
297     /* Get display time now. If we do it later, we may miss a PTS. */
298     p_spu->begin_date = p_spu->end_date
299                     = DECODER_FIFO_START(*p_spudec->p_fifo)->i_pts;
300
301     /* Allocate the temporary buffer we will parse */
302     p_src = malloc( p_spudec->i_rle_size );
303
304     if( p_src == NULL )
305     {
306         intf_ErrMsg( "spudec error: could not allocate p_src" );
307         vout_DestroySubPicture( p_spudec->p_vout, p_spu );
308         return;
309     }
310
311     /* Get RLE data */
312     GetChunk( &p_spudec->bit_stream, p_src, p_spudec->i_rle_size );
313
314 #if 0
315     /* Dump the subtitle info */
316     intf_WarnHexDump( 0, p_spu->p_data, p_spudec->i_rle_size );
317 #endif
318
319     /* Getting the control part */
320     if( ParseControlSequences( p_spudec, p_spu ) )
321     {
322         /* There was a parse error, delete the subpicture */
323         free( p_src );
324         vout_DestroySubPicture( p_spudec->p_vout, p_spu );
325         return;
326     }
327
328     if( ParseRLE( p_src, p_spu ) )
329     {
330         /* There was a parse error, delete the subpicture */
331         free( p_src );
332         vout_DestroySubPicture( p_spudec->p_vout, p_spu );
333         return;
334     }
335
336     intf_WarnMsg( 1, "spudec: got a valid %ix%i subtitle at (%i,%i), "
337                      "RLE offsets: 0x%x 0x%x",
338                   p_spu->i_width, p_spu->i_height, p_spu->i_x, p_spu->i_y,
339                   p_spu->type.spu.i_offset[0], p_spu->type.spu.i_offset[1] );
340
341     /* SPU is finished - we can ask the video output to display it */
342     vout_DisplaySubPicture( p_spudec->p_vout, p_spu );
343
344     /* Clean up */
345     free( p_src );
346 }
347
348 /*****************************************************************************
349  * ParseControlSequences: parse all SPU control sequences
350  *****************************************************************************
351  * This is the most important part in SPU decoding. We get dates, palette
352  * information, coordinates, and so on. For more information on the
353  * subtitles format, see http://sam.zoy.org/doc/dvd/subtitles/index.html
354  *****************************************************************************/
355 static int ParseControlSequences( spudec_thread_t *p_spudec,
356                                   subpicture_t * p_spu )
357 {
358     /* Our current index in the SPU packet */
359     int i_index = p_spudec->i_rle_size + 4;
360
361     /* The next start-of-control-sequence index and the previous one */
362     int i_next_index = 0, i_prev_index;
363
364     /* Command time and date */
365     u8  i_command;
366     int i_date;
367
368     do
369     {
370         /* Get the control sequence date */
371         i_date = GetBits( &p_spudec->bit_stream, 16 );
372  
373         /* Next offset */
374         i_prev_index = i_next_index;
375         i_next_index = GetBits( &p_spudec->bit_stream, 16 );
376  
377         /* Skip what we just read */
378         i_index += 4;
379  
380         do
381         {
382             i_command = GetBits( &p_spudec->bit_stream, 8 );
383             i_index++;
384  
385             switch( i_command )
386             {
387                 case SPU_CMD_FORCE_DISPLAY:
388  
389                     /* 00 (force displaying) */
390                     break;
391  
392                 /* Convert the dates in seconds to PTS values */
393                 case SPU_CMD_START_DISPLAY:
394  
395                     /* 01 (start displaying) */
396                     p_spu->begin_date += ( i_date * 11000 );
397  
398                     break;
399  
400                 case SPU_CMD_STOP_DISPLAY:
401  
402                     /* 02 (stop displaying) */
403                     p_spu->end_date += ( i_date * 11000 );
404  
405                     break;
406  
407                 case SPU_CMD_SET_PALETTE:
408  
409                     /* 03xxxx (palette) - trashed */
410                     RemoveBits( &p_spudec->bit_stream, 16 );
411                     i_index += 2;
412  
413                     break;
414  
415                 case SPU_CMD_SET_ALPHACHANNEL:
416  
417                     /* 04xxxx (alpha channel) - trashed */
418                     RemoveBits( &p_spudec->bit_stream, 16 );
419                     i_index += 2;
420  
421                     break;
422  
423                 case SPU_CMD_SET_COORDINATES:
424  
425                     /* 05xxxyyyxxxyyy (coordinates) */
426                     p_spu->i_x = GetBits( &p_spudec->bit_stream, 12 );
427                     p_spu->i_width = GetBits( &p_spudec->bit_stream, 12 )
428                                       - p_spu->i_x + 1;
429  
430                     p_spu->i_y = GetBits( &p_spudec->bit_stream, 12 );
431                     p_spu->i_height = GetBits( &p_spudec->bit_stream, 12 )
432                                        - p_spu->i_y + 1;
433  
434                     i_index += 6;
435  
436                     break;
437  
438                 case SPU_CMD_SET_OFFSETS:
439  
440                     /* 06xxxxyyyy (byte offsets) */
441                     p_spu->type.spu.i_offset[0] =
442                         GetBits( &p_spudec->bit_stream, 16 ) - 4;
443  
444                     p_spu->type.spu.i_offset[1] =
445                         GetBits( &p_spudec->bit_stream, 16 ) - 4;
446  
447                     i_index += 4;
448  
449                     break;
450  
451                 case SPU_CMD_END:
452  
453                     /* ff (end) */
454                     break;
455  
456                 default:
457  
458                     /* xx (unknown command) */
459                     intf_ErrMsg( "spudec error: unknown command 0x%.2x",
460                                  i_command );
461                     return( 1 );
462             }
463
464         } while( i_command != SPU_CMD_END );
465
466     } while( i_index == i_next_index );
467
468     /* Check that the last index matches the previous one */
469     if( i_next_index != i_prev_index )
470     {
471         intf_ErrMsg( "spudec error: index mismatch (0x%.4x != 0x%.4x)",
472                      i_next_index, i_prev_index );
473         return( 1 );
474     }
475
476     if( i_index > p_spudec->i_spu_size )
477     {
478         intf_ErrMsg( "spudec error: uh-oh, we went too far (0x%.4x > 0x%.4x)",
479                      i_index, p_spudec->i_spu_size );
480         return( 1 );
481     }
482
483     /* Get rid of padding bytes */
484     switch( p_spudec->i_spu_size - i_index )
485     {
486         case 1:
487
488             RemoveBits( &p_spudec->bit_stream, 8 );
489             i_index++;
490
491         case 0:
492
493             /* Zero or one padding byte, quite usual */
494
495             break;
496
497         default:
498
499             /* More than one padding byte - this is very strange, but
500              * we can deal with it */
501             intf_WarnMsg( 2, "spudec warning: %i padding bytes, we usually "
502                              "get 1 or none",
503                           p_spudec->i_spu_size - i_index );
504
505             while( i_index < p_spudec->i_spu_size )
506             {
507                 RemoveBits( &p_spudec->bit_stream, 8 );
508                 i_index++;
509             }
510
511             break;
512     }
513
514     /* Successfully parsed ! */
515     return( 0 );
516 }
517
518 /*****************************************************************************
519  * ParseRLE: parse the RLE part of the subtitle
520  *****************************************************************************
521  * This part parses the subtitle graphical data and stores it in a more
522  * convenient structure for later decoding. For more information on the
523  * subtitles format, see http://sam.zoy.org/doc/dvd/subtitles/index.html
524  *****************************************************************************/
525 static int ParseRLE( u8 *p_src, subpicture_t * p_spu )
526 {
527     unsigned int i_code;
528     unsigned int i_id = 0;
529
530     unsigned int i_width = p_spu->i_width;
531     unsigned int i_height = p_spu->i_height;
532     unsigned int i_x, i_y;
533
534     u16 *p_dest = (u16 *)p_spu->p_data;
535
536     /* The subtitles are interlaced, we need two offsets */
537     unsigned int  pi_table[ 2 ];
538     unsigned int *pi_offset;
539
540     pi_table[ 0 ] = p_spu->type.spu.i_offset[ 0 ] << 1;
541     pi_table[ 1 ] = p_spu->type.spu.i_offset[ 1 ] << 1;
542
543     for( i_y = 0 ; i_y < i_height ; i_y++ )
544     {
545         pi_offset = pi_table + i_id;
546
547         for( i_x = 0 ; i_x < i_width ; i_x += i_code >> 2 )
548         {
549             i_code = AddNibble( 0, p_src, pi_offset );
550
551             if( i_code < 0x04 )
552             {
553                 i_code = AddNibble( i_code, p_src, pi_offset );
554
555                 if( i_code < 0x10 )
556                 {
557                     i_code = AddNibble( i_code, p_src, pi_offset );
558
559                     if( i_code < 0x040 )
560                     {
561                         i_code = AddNibble( i_code, p_src, pi_offset );
562
563                         if( i_code < 0x0100 )
564                         {
565                             /* If the 14 first bits are set to 0, then it's a
566                              * new line. We emulate it. */
567                             if( i_code < 0x0004 )
568                             {
569                                 i_code |= ( i_width - i_x ) << 2;
570                             }
571                             else
572                             {
573                                 /* We have a boo boo ! */
574                                 intf_ErrMsg( "spudec error: unknown RLE code "
575                                              "0x%.4x", i_code );
576                                 return( 1 );
577                             }
578                         }
579                     }
580                 }
581             }
582
583             if( ( (i_code >> 2) + i_x + i_y * i_width ) > i_height * i_width )
584             {
585                 intf_ErrMsg( "spudec error: out of bounds, %i at (%i,%i) is "
586                              "out of %ix%i",
587                              i_code >> 2, i_x, i_y, i_width, i_height);
588                 return( 1 );
589             }
590
591             /* We got a valid code, store it */
592             *p_dest++ = i_code;
593         }
594
595         /* Check that we didn't go too far */
596         if( i_x > i_width )
597         {
598             intf_ErrMsg( "spudec error: i_x overflowed, %i > %i",
599                          i_x, i_width );
600             return( 1 );
601         }
602
603         /* Byte-align the stream */
604         if( *pi_offset & 0x1 )
605         {
606             (*pi_offset)++;
607         }
608
609         /* Swap fields */
610         i_id = ~i_id & 0x1;
611     }
612
613     /* FIXME: we shouldn't need these padding bytes */
614     while( i_y < i_height )
615     {
616         *p_dest++ = i_width << 2;
617         i_y++;
618     }
619
620     return( 0 );
621 }
622