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