]> git.sesse.net Git - vlc/blob - plugins/spudec/spu_decoder.c
* modified the gtk interface to save an empty <string> option as a NULL pointer
[vlc] / plugins / spudec / spu_decoder.c
1 /*****************************************************************************
2  * spu_decoder.c : spu decoder thread
3  *****************************************************************************
4  * Copyright (C) 2000-2001 VideoLAN
5  * $Id: spu_decoder.c,v 1.13 2002/03/15 18:20:27 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 <stdlib.h>                                      /* malloc(), free() */
28 #include <string.h>                                    /* memcpy(), memset() */
29
30 #include <videolan/vlc.h>
31
32 #ifdef HAVE_UNISTD_H
33 #   include <unistd.h>                                           /* getpid() */
34 #endif
35
36 #ifdef WIN32                   /* getpid() for win32 is located in process.h */
37 #   include <process.h>
38 #endif
39
40 #include "video.h"
41 #include "video_output.h"
42
43 #include "stream_control.h"
44 #include "input_ext-dec.h"
45
46 #include "spu_decoder.h"
47
48 /*****************************************************************************
49  * Local prototypes
50  *****************************************************************************/
51 static int  decoder_Probe ( u8 * );
52 static int  decoder_Run   ( decoder_config_t * );
53 static int  InitThread    ( spudec_thread_t * );
54 static void EndThread     ( spudec_thread_t * );
55
56 static int  SyncPacket           ( spudec_thread_t * );
57 static void ParsePacket          ( spudec_thread_t * );
58 static int  ParseControlSequences( spudec_thread_t *, subpicture_t * );
59 static int  ParseRLE             ( spudec_thread_t *, subpicture_t *, u8 * );
60 static void RenderSPU            ( const vout_thread_t *, picture_t *,
61                                    const subpicture_t * );
62
63 /*****************************************************************************
64  * Capabilities
65  *****************************************************************************/
66 void _M( spudec_getfunctions )( function_list_t * p_function_list )
67 {
68     p_function_list->functions.dec.pf_probe = decoder_Probe;
69     p_function_list->functions.dec.pf_run   = decoder_Run;
70 }
71
72 /*****************************************************************************
73  * Build configuration tree.
74  *****************************************************************************/
75 MODULE_CONFIG_START
76 MODULE_CONFIG_STOP
77
78 MODULE_INIT_START
79     SET_DESCRIPTION( "DVD subtitles decoder module" )
80     ADD_CAPABILITY( DECODER, 50 )
81 MODULE_INIT_STOP
82
83 MODULE_ACTIVATE_START
84     _M( spudec_getfunctions )( &p_module->p_functions->dec );
85 MODULE_ACTIVATE_STOP
86
87 MODULE_DEACTIVATE_START
88 MODULE_DEACTIVATE_STOP
89
90 /*****************************************************************************
91  * decoder_Probe: probe the decoder and return score
92  *****************************************************************************
93  * Tries to launch a decoder and return score so that the interface is able 
94  * to chose.
95  *****************************************************************************/
96 static int decoder_Probe( u8 *pi_type )
97 {
98     return ( *pi_type == DVD_SPU_ES ) ? 0 : -1;
99 }
100
101 /*****************************************************************************
102  * decoder_Run: this function is called just after the thread is created
103  *****************************************************************************/
104 static int decoder_Run( decoder_config_t * p_config )
105 {
106     spudec_thread_t *     p_spudec;
107    
108     intf_WarnMsg( 3, "spudec: thread launched. Initializing ..." );
109
110     /* Allocate the memory needed to store the thread's structure */
111     p_spudec = (spudec_thread_t *)malloc( sizeof(spudec_thread_t) );
112
113     if ( p_spudec == NULL )
114     {
115         intf_ErrMsg( "spudec error: not enough memory "
116                      "for spudec_CreateThread() to create the new thread" );
117         DecoderError( p_config->p_decoder_fifo );
118         return( -1 );
119     }
120     
121     /*
122      * Initialize the thread properties
123      */
124     p_spudec->p_config = p_config;
125
126     p_spudec->p_fifo = p_config->p_decoder_fifo;
127         
128     /*
129      * Initialize thread and free configuration
130      */
131     p_spudec->p_fifo->b_error = InitThread( p_spudec );
132
133     /*
134      * Main loop - it is not executed if an error occured during
135      * initialization
136      */
137     while( (!p_spudec->p_fifo->b_die) && (!p_spudec->p_fifo->b_error) )
138     {
139         if( !SyncPacket( p_spudec ) )
140         {
141             ParsePacket( p_spudec );
142         }
143     }
144
145     /*
146      * Error loop
147      */
148     if( p_spudec->p_fifo->b_error )
149     {
150         DecoderError( p_spudec->p_fifo );
151     }
152
153     /* End of thread */
154     EndThread( p_spudec );
155
156     if( p_spudec->p_fifo->b_error )
157     {
158         return( -1 );
159     }
160    
161     return( 0 );
162
163 }
164
165 /* following functions are local */
166
167 /*****************************************************************************
168  * InitThread: initialize spu decoder thread
169  *****************************************************************************
170  * This function is called from RunThread and performs the second step of the
171  * initialization. It returns 0 on success. Note that the thread's flag are not
172  * modified inside this function.
173  *****************************************************************************/
174 static int InitThread( spudec_thread_t *p_spudec )
175 {
176     /* Find an available video output */
177     vlc_mutex_lock( &p_vout_bank->lock );
178
179     while( p_vout_bank->i_count == 0 )
180     {
181         vlc_mutex_unlock( &p_vout_bank->lock );
182
183         if( p_spudec->p_fifo->b_die || p_spudec->p_fifo->b_error )
184         {
185             return( -1 );
186         }
187
188         msleep( VOUT_OUTMEM_SLEEP );
189         vlc_mutex_lock( &p_vout_bank->lock );
190     }
191
192     /* Take the first video output FIXME: take the best one */
193     p_spudec->p_vout = p_vout_bank->pp_vout[ 0 ];
194     vlc_mutex_unlock( &p_vout_bank->lock );
195     InitBitstream( &p_spudec->bit_stream,
196                    p_spudec->p_config->p_decoder_fifo, NULL, NULL );
197
198     /* Mark thread as running and return */
199     return( 0 );
200 }
201
202 /*****************************************************************************
203  * EndThread: thread destruction
204  *****************************************************************************
205  * This function is called when the thread ends after a sucessful
206  * initialization.
207  *****************************************************************************/
208 static void EndThread( spudec_thread_t *p_spudec )
209 {
210     free( p_spudec );
211 }
212
213 /*****************************************************************************
214  * SyncPacket: get in sync with the stream
215  *****************************************************************************
216  * This function makes a few sanity checks and returns 0 if it looks like we
217  * are at the beginning of a subpicture packet.
218  *****************************************************************************/
219 static int SyncPacket( spudec_thread_t *p_spudec )
220 {
221     /* Re-align the buffer on an 8-bit boundary */
222     RealignBits( &p_spudec->bit_stream );
223
224     /* The total SPU packet size, often bigger than a PS packet */
225     p_spudec->i_spu_size = GetBits( &p_spudec->bit_stream, 16 );
226
227     /* The RLE stuff size (remove 4 because we just read 32 bits) */
228     p_spudec->i_rle_size = ShowBits( &p_spudec->bit_stream, 16 ) - 4;
229
230     /* If the values we got are a bit strange, skip packet */
231     if( !p_spudec->i_spu_size
232          || ( p_spudec->i_rle_size >= p_spudec->i_spu_size ) )
233     {
234         return( 1 );
235     }
236
237     RemoveBits( &p_spudec->bit_stream, 16 );
238
239     return( 0 );
240 }
241
242 /*****************************************************************************
243  * ParsePacket: parse an SPU packet and send it to the video output
244  *****************************************************************************
245  * This function parses the SPU packet and, if valid, sends it to the
246  * video output.
247  *****************************************************************************/
248 static void ParsePacket( spudec_thread_t *p_spudec )
249 {
250     subpicture_t * p_spu;
251     u8           * p_src;
252     unsigned int   i_offset;
253
254     intf_WarnMsg( 3, "spudec: trying to gather a 0x%.2x long subtitle",
255                   p_spudec->i_spu_size );
256
257     /* We cannot display a subpicture with no date */
258     if( p_spudec->p_fifo->p_first->i_pts == 0 )
259     {
260         intf_WarnMsg( 3, "spudec error: subtitle without a date" );
261         return;
262     }
263
264     /* Allocate the subpicture internal data. */
265     p_spu = vout_CreateSubPicture( p_spudec->p_vout, MEMORY_SUBPICTURE,
266                                    sizeof( struct subpicture_sys_s )
267                                     + p_spudec->i_rle_size * 4 );
268     /* Rationale for the "p_spudec->i_rle_size * 4": we are going to
269      * expand the RLE stuff so that we won't need to read nibbles later
270      * on. This will speed things up a lot. Plus, we'll only need to do
271      * this stupid interlacing stuff once. */
272
273     if( p_spu == NULL )
274     {
275         return;
276     }
277
278     /* Fill the p_spu structure */
279     p_spu->pf_render = RenderSPU;
280     p_spu->p_sys->p_data = (void*)p_spu->p_sys
281                             + sizeof( struct subpicture_sys_s );
282     p_spu->p_sys->b_palette = 0;
283
284     /* Get display time now. If we do it later, we may miss the PTS. */
285     p_spu->p_sys->i_pts = p_spudec->p_fifo->p_first->i_pts;
286
287     /* Allocate the temporary buffer we will parse */
288     p_src = malloc( p_spudec->i_rle_size );
289
290     if( p_src == NULL )
291     {
292         intf_ErrMsg( "spudec error: could not allocate p_src" );
293         vout_DestroySubPicture( p_spudec->p_vout, p_spu );
294         return;
295     }
296
297     /* Get RLE data */
298     for( i_offset = 0;
299          i_offset + SPU_CHUNK_SIZE < p_spudec->i_rle_size;
300          i_offset += SPU_CHUNK_SIZE )
301     {
302         GetChunk( &p_spudec->bit_stream, p_src + i_offset, SPU_CHUNK_SIZE );
303
304         /* Abort subtitle parsing if we were requested to stop */
305         if( p_spudec->p_fifo->b_die )
306         {
307             free( p_src );
308             vout_DestroySubPicture( p_spudec->p_vout, p_spu );
309             return;
310         }
311     }
312
313     GetChunk( &p_spudec->bit_stream, p_src + i_offset,
314               p_spudec->i_rle_size - i_offset );
315
316 #if 0
317     /* Dump the subtitle info */
318     intf_WarnHexDump( 5, p_spu->p_sys->p_data, p_spudec->i_rle_size );
319 #endif
320
321     /* Getting the control part */
322     if( ParseControlSequences( p_spudec, p_spu ) )
323     {
324         /* There was a parse error, delete the subpicture */
325         free( p_src );
326         vout_DestroySubPicture( p_spudec->p_vout, p_spu );
327         return;
328     }
329
330     /* At this point, no more GetBit() command is needed, so we have all
331      * the data we need to tell whether the subtitle is valid. Thus we
332      * try to display it and we ignore b_die. */
333
334     if( ParseRLE( p_spudec, p_spu, p_src ) )
335     {
336         /* There was a parse error, delete the subpicture */
337         free( p_src );
338         vout_DestroySubPicture( p_spudec->p_vout, p_spu );
339         return;
340     }
341
342     intf_WarnMsg( 3, "spudec: total size: 0x%x, RLE offsets: 0x%x 0x%x",
343                   p_spudec->i_spu_size,
344                   p_spu->p_sys->pi_offset[0], p_spu->p_sys->pi_offset[1] );
345
346     /* SPU is finished - we can ask the video output to display it */
347     vout_DisplaySubPicture( p_spudec->p_vout, p_spu );
348
349     /* Clean up */
350     free( p_src );
351 }
352
353 /*****************************************************************************
354  * ParseControlSequences: parse all SPU control sequences
355  *****************************************************************************
356  * This is the most important part in SPU decoding. We get dates, palette
357  * information, coordinates, and so on. For more information on the
358  * subtitles format, see http://sam.zoy.org/doc/dvd/subtitles/index.html
359  *****************************************************************************/
360 static int ParseControlSequences( spudec_thread_t *p_spudec,
361                                   subpicture_t * p_spu )
362 {
363     /* Our current index in the SPU packet */
364     int i_index = p_spudec->i_rle_size + 4;
365
366     /* The next start-of-control-sequence index and the previous one */
367     int i_next_seq, i_cur_seq;
368
369     /* Command time and date */
370     u8  i_command;
371     int i_date;
372
373     /* Dummy stuff */
374     u8 *pi_color;
375     int i;
376
377     /* XXX: temporary variables */
378     boolean_t b_force_display = 0;
379
380     /* Initialize the structure */
381     p_spu->i_start = p_spu->i_stop = 0;
382     p_spu->b_ephemer = 0;
383
384     do
385     {
386         /* Get the control sequence date */
387         i_date = GetBits( &p_spudec->bit_stream, 16 );
388  
389         /* Next offset */
390         i_cur_seq = i_index;
391         i_next_seq = GetBits( &p_spudec->bit_stream, 16 );
392  
393         /* Skip what we just read */
394         i_index += 4;
395  
396         do
397         {
398             i_command = GetBits( &p_spudec->bit_stream, 8 );
399             i_index++;
400  
401             switch( i_command )
402             {
403                 case SPU_CMD_FORCE_DISPLAY:
404
405                     /* 00 (force displaying) */
406                     p_spu->i_start = p_spu->p_sys->i_pts + ( i_date * 11000 );
407                     b_force_display = 1;
408  
409                     break;
410  
411                 /* Convert the dates in seconds to PTS values */
412                 case SPU_CMD_START_DISPLAY:
413  
414                     /* 01 (start displaying) */
415                     p_spu->i_start = p_spu->p_sys->i_pts + ( i_date * 11000 );
416  
417                     break;
418  
419                 case SPU_CMD_STOP_DISPLAY:
420  
421                     /* 02 (stop displaying) */
422                     p_spu->i_stop = p_spu->p_sys->i_pts + ( i_date * 11000 );
423  
424                     break;
425  
426                 case SPU_CMD_SET_PALETTE:
427  
428                     /* 03xxxx (palette) */
429                     if( p_spudec->p_config->p_demux_data )
430                     {
431                         p_spu->p_sys->b_palette = 1;
432                         for( i = 0; i < 4 ; i++ )
433                         {
434                             pi_color = (u8*)p_spudec->p_config->p_demux_data
435                                     + 4 * GetBits( &p_spudec->bit_stream, 4 );
436                             p_spu->p_sys->pi_yuv[3-i][0] = pi_color[2];
437                             p_spu->p_sys->pi_yuv[3-i][1] = pi_color[0];
438                             p_spu->p_sys->pi_yuv[3-i][2] = pi_color[1];
439                         }
440                     }
441                     else
442                     {
443                         RemoveBits( &p_spudec->bit_stream, 16 );
444                     }
445                     i_index += 2;
446  
447                     break;
448  
449                 case SPU_CMD_SET_ALPHACHANNEL:
450  
451                     /* 04xxxx (alpha channel) */
452                     for( i = 0; i < 4 ; i++ )
453                     {
454                         p_spu->p_sys->pi_alpha[3-i]
455                                        = GetBits( &p_spudec->bit_stream, 4 );
456                     }
457                     i_index += 2;
458  
459                     break;
460  
461                 case SPU_CMD_SET_COORDINATES:
462  
463                     /* 05xxxyyyxxxyyy (coordinates) */
464                     p_spu->i_x = GetBits( &p_spudec->bit_stream, 12 );
465                     p_spu->i_width = GetBits( &p_spudec->bit_stream, 12 )
466                                       - p_spu->i_x + 1;
467  
468                     p_spu->i_y = GetBits( &p_spudec->bit_stream, 12 );
469                     p_spu->i_height = GetBits( &p_spudec->bit_stream, 12 )
470                                        - p_spu->i_y + 1;
471  
472                     i_index += 6;
473  
474                     break;
475  
476                 case SPU_CMD_SET_OFFSETS:
477  
478                     /* 06xxxxyyyy (byte offsets) */
479                     p_spu->p_sys->pi_offset[0] =
480                         GetBits( &p_spudec->bit_stream, 16 ) - 4;
481  
482                     p_spu->p_sys->pi_offset[1] =
483                         GetBits( &p_spudec->bit_stream, 16 ) - 4;
484  
485                     i_index += 4;
486  
487                     break;
488  
489                 case SPU_CMD_END:
490  
491                     /* ff (end) */
492                     break;
493  
494                 default:
495  
496                     /* xx (unknown command) */
497                     intf_ErrMsg( "spudec error: unknown command 0x%.2x",
498                                  i_command );
499                     return( 1 );
500             }
501
502             /* We need to check for quit commands here */
503             if( p_spudec->p_fifo->b_die )
504             {
505                 return( 1 );
506             }
507
508         } while( i_command != SPU_CMD_END );
509
510     } while( i_index == i_next_seq );
511
512     /* Check that the next sequence index matches the current one */
513     if( i_next_seq != i_cur_seq )
514     {
515         intf_ErrMsg( "spudec error: index mismatch (0x%.4x != 0x%.4x)",
516                      i_next_seq, i_cur_seq );
517         return( 1 );
518     }
519
520     if( i_index > p_spudec->i_spu_size )
521     {
522         intf_ErrMsg( "spudec error: uh-oh, we went too far (0x%.4x > 0x%.4x)",
523                      i_index, p_spudec->i_spu_size );
524         return( 1 );
525     }
526
527     if( !p_spu->i_start )
528     {
529         intf_ErrMsg( "spudec error: no `start display' command" );
530     }
531
532     if( !p_spu->i_stop )
533     {
534         /* This subtitle will live for 5 seconds or until the next subtitle */
535         p_spu->i_stop = p_spu->i_start + 500 * 11000;
536         p_spu->b_ephemer = 1;
537     }
538
539     /* Get rid of padding bytes */
540     switch( p_spudec->i_spu_size - i_index )
541     {
542         /* Zero or one padding byte, quite usual */
543         case 1:
544             RemoveBits( &p_spudec->bit_stream, 8 );
545             i_index++;
546         case 0:
547             break;
548
549         /* More than one padding byte - this is very strange, but
550          * we can deal with it */
551         default:
552             intf_WarnMsg( 2, "spudec warning: %i padding bytes, we usually "
553                              "get 0 or 1 of them",
554                           p_spudec->i_spu_size - i_index );
555
556             while( i_index < p_spudec->i_spu_size )
557             {
558                 RemoveBits( &p_spudec->bit_stream, 8 );
559                 i_index++;
560             }
561
562             break;
563     }
564
565     if( b_force_display )
566     {
567         intf_ErrMsg( "spudec: \"force display\" command" );
568         intf_ErrMsg( "spudec: send mail to <sam@zoy.org> if you "
569                      "want to help debugging this" );
570     }
571
572     /* Successfully parsed ! */
573     return( 0 );
574 }
575
576 /*****************************************************************************
577  * ParseRLE: parse the RLE part of the subtitle
578  *****************************************************************************
579  * This part parses the subtitle graphical data and stores it in a more
580  * convenient structure for later decoding. For more information on the
581  * subtitles format, see http://sam.zoy.org/doc/dvd/subtitles/index.html
582  *****************************************************************************/
583 static int ParseRLE( spudec_thread_t *p_spudec,
584                      subpicture_t * p_spu, u8 * p_src )
585 {
586     unsigned int i_code;
587
588     unsigned int i_width = p_spu->i_width;
589     unsigned int i_height = p_spu->i_height;
590     unsigned int i_x, i_y;
591
592     u16 *p_dest = (u16 *)p_spu->p_sys->p_data;
593
594     /* The subtitles are interlaced, we need two offsets */
595     unsigned int  i_id = 0;                   /* Start on the even SPU layer */
596     unsigned int  pi_table[ 2 ];
597     unsigned int *pi_offset;
598
599     boolean_t b_empty_top = 1,
600               b_empty_bottom = 0;
601     unsigned int i_skipped_top = 0,
602                  i_skipped_bottom = 0;
603
604     /* Colormap statistics */
605     int i_border = -1;
606     int stats[4]; stats[0] = stats[1] = stats[2] = stats[3] = 0;
607
608     pi_table[ 0 ] = p_spu->p_sys->pi_offset[ 0 ] << 1;
609     pi_table[ 1 ] = p_spu->p_sys->pi_offset[ 1 ] << 1;
610
611     for( i_y = 0 ; i_y < i_height ; i_y++ )
612     {
613         pi_offset = pi_table + i_id;
614
615         for( i_x = 0 ; i_x < i_width ; i_x += i_code >> 2 )
616         {
617             i_code = AddNibble( 0, p_src, pi_offset );
618
619             if( i_code < 0x04 )
620             {
621                 i_code = AddNibble( i_code, p_src, pi_offset );
622
623                 if( i_code < 0x10 )
624                 {
625                     i_code = AddNibble( i_code, p_src, pi_offset );
626
627                     if( i_code < 0x040 )
628                     {
629                         i_code = AddNibble( i_code, p_src, pi_offset );
630
631                         if( i_code < 0x0100 )
632                         {
633                             /* If the 14 first bits are set to 0, then it's a
634                              * new line. We emulate it. */
635                             if( i_code < 0x0004 )
636                             {
637                                 i_code |= ( i_width - i_x ) << 2;
638                             }
639                             else
640                             {
641                                 /* We have a boo boo ! */
642                                 intf_ErrMsg( "spudec error: unknown RLE code "
643                                              "0x%.4x", i_code );
644                                 return( 1 );
645                             }
646                         }
647                     }
648                 }
649             }
650
651             if( ( (i_code >> 2) + i_x + i_y * i_width ) > i_height * i_width )
652             {
653                 intf_ErrMsg( "spudec error: out of bounds, %i at (%i,%i) is "
654                              "out of %ix%i",
655                              i_code >> 2, i_x, i_y, i_width, i_height );
656                 return( 1 );
657             }
658
659             /* Try to find the border color */
660             if( p_spu->p_sys->pi_alpha[ i_code & 0x3 ] != 0x00 )
661             {
662                 i_border = i_code & 0x3;
663                 stats[i_border] += i_code >> 2;
664             }
665
666             if( (i_code >> 2) == i_width
667                  && p_spu->p_sys->pi_alpha[ i_code & 0x3 ] == 0x00 )
668             {
669                 if( b_empty_top )
670                 {
671                     /* This is a blank top line, we skip it */
672                     i_skipped_top++;
673                 }
674                 else
675                 {
676                     /* We can't be sure the current lines will be skipped,
677                      * so we store the code just in case. */
678                     *p_dest++ = i_code;
679
680                     b_empty_bottom = 1;
681                     i_skipped_bottom++;
682                 }
683             }
684             else
685             {
686                 /* We got a valid code, store it */
687                 *p_dest++ = i_code;
688
689                 /* Valid code means no blank line */
690                 b_empty_top = 0;
691                 b_empty_bottom = 0;
692                 i_skipped_bottom = 0;
693             }
694         }
695
696         /* Check that we didn't go too far */
697         if( i_x > i_width )
698         {
699             intf_ErrMsg( "spudec error: i_x overflowed, %i > %i",
700                          i_x, i_width );
701             return( 1 );
702         }
703
704         /* Byte-align the stream */
705         if( *pi_offset & 0x1 )
706         {
707             (*pi_offset)++;
708         }
709
710         /* Swap fields */
711         i_id = ~i_id & 0x1;
712     }
713
714     /* We shouldn't get any padding bytes */
715     if( i_y < i_height )
716     {
717         intf_ErrMsg( "spudec: padding bytes found in RLE sequence" );
718         intf_ErrMsg( "spudec: send mail to <sam@zoy.org> if you "
719                      "want to help debugging this" );
720
721         /* Skip them just in case */
722         while( i_y < i_height )
723         {
724             *p_dest++ = i_width << 2;
725             i_y++;
726         }
727
728         return( 1 );
729     }
730
731     intf_WarnMsg( 3, "spudec: valid subtitle, size: %ix%i, position: %i,%i",
732                   p_spu->i_width, p_spu->i_height, p_spu->i_x, p_spu->i_y );
733
734     /* Crop if necessary */
735     if( i_skipped_top || i_skipped_bottom )
736     {
737         p_spu->i_y += i_skipped_top;
738         p_spu->i_height -= i_skipped_top + i_skipped_bottom;
739
740         intf_WarnMsg( 3, "spudec: cropped to: %ix%i, position: %i,%i",
741                       p_spu->i_width, p_spu->i_height, p_spu->i_x, p_spu->i_y );
742     }
743
744     /* Handle color if no palette was found */
745     if( !p_spu->p_sys->b_palette )
746     {
747         int i, i_inner = -1, i_shade = -1;
748
749         /* Set the border color */
750         p_spu->p_sys->pi_yuv[i_border][0] = 0x00;
751         p_spu->p_sys->pi_yuv[i_border][1] = 0x80;
752         p_spu->p_sys->pi_yuv[i_border][2] = 0x80;
753         stats[i_border] = 0;
754
755         /* Find the inner colors */
756         for( i = 0 ; i < 4 && i_inner == -1 ; i++ )
757         {
758             if( stats[i] )
759             {
760                 i_inner = i;
761             }
762         }
763
764         for(       ; i < 4 && i_shade == -1 ; i++ )
765         {
766             if( stats[i] )
767             {
768                 if( stats[i] > stats[i_inner] )
769                 {
770                     i_shade = i_inner;
771                     i_inner = i;
772                 }
773                 else
774                 {
775                     i_shade = i;
776                 }
777             }
778         }
779
780         /* Set the inner color */
781         if( i_inner != -1 )
782         {
783             p_spu->p_sys->pi_yuv[i_inner][0] = 0xff;
784             p_spu->p_sys->pi_yuv[i_inner][1] = 0x80;
785             p_spu->p_sys->pi_yuv[i_inner][2] = 0x80;
786         }
787
788         /* Set the anti-aliasing color */
789         if( i_shade != -1 )
790         {
791             p_spu->p_sys->pi_yuv[i_shade][0] = 0x80;
792             p_spu->p_sys->pi_yuv[i_shade][1] = 0x80;
793             p_spu->p_sys->pi_yuv[i_shade][2] = 0x80;
794         }
795
796         intf_WarnMsg( 3, "spudec: using custom palette (border %i, inner %i, "
797                          "shade %i)", i_border, i_inner, i_shade );
798     }
799
800     return( 0 );
801 }
802
803 /*****************************************************************************
804  * RenderSPU: draw an SPU on a picture
805  *****************************************************************************
806  * This is a fast implementation of the subpicture drawing code. The data
807  * has been preprocessed once, so we don't need to parse the RLE buffer again
808  * and again. Most sanity checks are already done so that this routine can be
809  * as fast as possible.
810  *****************************************************************************/
811 static void RenderSPU( const vout_thread_t *p_vout, picture_t *p_pic,
812                        const subpicture_t *p_spu )
813 {
814     /* Common variables */
815     u16  p_clut16[4];
816     u8  *p_dest;
817     u16 *p_source = (u16 *)p_spu->p_sys->p_data;
818
819     int i_x, i_y;
820     int i_len, i_color;
821
822     /* RGB-specific */
823     int i_xscale, i_yscale, i_width, i_height, i_ytmp, i_yreal, i_ynext;
824
825     switch( p_vout->output.i_chroma )
826     {
827     /* I420 target, no scaling */
828     case FOURCC_I420:
829     case FOURCC_IYUV:
830     case FOURCC_YV12:
831
832     p_dest = p_pic->p->p_pixels + p_spu->i_x + p_spu->i_width
833               + p_vout->output.i_width * ( p_spu->i_y + p_spu->i_height );
834
835     /* Draw until we reach the bottom of the subtitle */
836     for( i_y = p_spu->i_height * p_vout->output.i_width ;
837          i_y ;
838          i_y -= p_vout->output.i_width )
839     {
840         /* Draw until we reach the end of the line */
841         for( i_x = p_spu->i_width ; i_x ; )
842         {
843             /* Get the RLE part, then draw the line */
844             i_color = *p_source & 0x3;
845
846             switch( p_spu->p_sys->pi_alpha[ i_color ] )
847             {
848                 case 0x00:
849                     i_x -= *p_source++ >> 2;
850                     break;
851
852                 case 0x0f:
853                     i_len = *p_source++ >> 2;
854                     memset( p_dest - i_x - i_y,
855                             p_spu->p_sys->pi_yuv[i_color][0], i_len );
856                     i_x -= i_len;
857                     break;
858
859                 default:
860                     /* FIXME: we should do transparency */
861                     i_len = *p_source++ >> 2;
862                     memset( p_dest - i_x - i_y,
863                             p_spu->p_sys->pi_yuv[i_color][0], i_len );
864                     i_x -= i_len;
865                     break;
866             }
867         }
868     }
869
870     break;
871
872     /* RV16 target, scaling */
873     case FOURCC_RV16:
874
875     /* FIXME: get this from the DVD */
876     p_clut16[0] = 0xaaaa; p_clut16[1] = 0xffff;
877     p_clut16[2] = 0x8888; p_clut16[3] = 0x0000;
878
879     i_xscale = ( p_vout->output.i_width << 6 ) / p_vout->render.i_width;
880     i_yscale = ( p_vout->output.i_height << 6 ) / p_vout->render.i_height;
881
882     i_width  = p_spu->i_width  * i_xscale;
883     i_height = p_spu->i_height * i_yscale;
884
885     p_dest = p_pic->p->p_pixels + ( i_width >> 6 ) * 2
886               /* Add the picture coordinates and the SPU coordinates */
887               + ( (p_spu->i_x * i_xscale) >> 6 ) * 2
888               + ( (p_spu->i_y * i_yscale) >> 6 ) * p_vout->output.i_width * 2;
889
890     /* Draw until we reach the bottom of the subtitle */
891     for( i_y = 0 ; i_y < i_height ; )
892     {
893         i_ytmp = i_y >> 6;
894         i_y += i_yscale;
895
896         /* Check whether we need to draw one line or more than one */
897         if( i_ytmp + 1 >= ( i_y >> 6 ) )
898         {
899             /* Just one line : we precalculate i_y >> 6 */
900             i_yreal = p_vout->output.i_width * 2 * i_ytmp;
901
902             /* Draw until we reach the end of the line */
903             for( i_x = i_width ; i_x ; )
904             {
905                 /* Get the RLE part, then draw the line */
906                 i_color = *p_source & 0x3;
907
908                 switch( p_spu->p_sys->pi_alpha[ i_color ] )
909                 {
910                 case 0x00:
911                     i_x -= i_xscale * ( *p_source++ >> 2 );
912                     break;
913
914                 case 0x0f:
915                     i_len = i_xscale * ( *p_source++ >> 2 );
916                     memset( p_dest - 2 * ( i_x >> 6 ) + i_yreal,
917                             p_clut16[ i_color ],
918                             2 * ( ( i_len >> 6 ) + 1 ) );
919                     i_x -= i_len;
920                     break;
921
922                 default:
923                     /* FIXME: we should do transparency */
924                     i_len = i_xscale * ( *p_source++ >> 2 );
925                     memset( p_dest - 2 * ( i_x >> 6 ) + i_yreal,
926                             p_clut16[ i_color ],
927                             2 * ( ( i_len >> 6 ) + 1 ) );
928                     i_x -= i_len;
929                     break;
930                 }
931
932             }
933         }
934         else
935         {
936             i_yreal = p_vout->output.i_width * 2 * i_ytmp;
937             i_ynext = p_vout->output.i_width * 2 * i_y >> 6;
938
939             /* Draw until we reach the end of the line */
940             for( i_x = i_width ; i_x ; )
941             {
942                 /* Get the RLE part, then draw as many lines as needed */
943                 i_color = *p_source & 0x3;
944
945                 switch( p_spu->p_sys->pi_alpha[ i_color ] )
946                 {
947                 case 0x00:
948                     i_x -= i_xscale * ( *p_source++ >> 2 );
949                     break;
950
951                 case 0x0f:
952                     i_len = i_xscale * ( *p_source++ >> 2 );
953                     for( i_ytmp = i_yreal ; i_ytmp < i_ynext ;
954                          i_ytmp += p_vout->output.i_width * 2 )
955                     {
956                         memset( p_dest - 2 * ( i_x >> 6 ) + i_ytmp,
957                                 p_clut16[ i_color ],
958                                 2 * ( ( i_len >> 6 ) + 1 ) );
959                     }
960                     i_x -= i_len;
961                     break;
962
963                 default:
964                     /* FIXME: we should do transparency */
965                     i_len = i_xscale * ( *p_source++ >> 2 );
966                     for( i_ytmp = i_yreal ; i_ytmp < i_ynext ;
967                          i_ytmp += p_vout->output.i_width * 2 )
968                     {
969                         memset( p_dest - 2 * ( i_x >> 6 ) + i_ytmp,
970                                 p_clut16[ i_color ],
971                                 2 * ( ( i_len >> 6 ) + 1 ) );
972                     }
973                     i_x -= i_len;
974                     break;
975                 }
976             }
977         }
978     }
979
980     break;
981
982     default:
983         intf_ErrMsg( "vout error: unknown chroma, can't render SPU" );
984         break;
985     }
986 }
987