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