Main Page | Modules | Class Hierarchy | Class List | Directories | File List | Class Members | File Members | Related Pages

parse.c

00001 /*****************************************************************************
00002  * parse.c: SPU parser
00003  *****************************************************************************
00004  * Copyright (C) 2000-2001, 2005 the VideoLAN team
00005  * $Id: parse.c 11709 2005-07-11 16:20:33Z massiot $
00006  *
00007  * Authors: Samuel Hocevar <[email protected]>
00008  *          Laurent Aimar <[email protected]>
00009  *          Gildas Bazin <[email protected]>
00010  *
00011  * This program is free software; you can redistribute it and/or modify
00012  * it under the terms of the GNU General Public License as published by
00013  * the Free Software Foundation; either version 2 of the License, or
00014  * (at your option) any later version.
00015  *
00016  * This program is distributed in the hope that it will be useful,
00017  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019  * GNU General Public License for more details.
00020  *
00021  * You should have received a copy of the GNU General Public License
00022  * along with this program; if not, write to the Free Software
00023  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
00024  *****************************************************************************/
00025 
00026 /*****************************************************************************
00027  * Preamble
00028  *****************************************************************************/
00029 #include <vlc/vlc.h>
00030 #include <vlc/vout.h>
00031 #include <vlc/decoder.h>
00032 
00033 #include "spudec.h"
00034 
00035 /*****************************************************************************
00036  * Local prototypes.
00037  *****************************************************************************/
00038 static int  ParseControlSeq( decoder_t *, subpicture_t *, subpicture_data_t *);
00039 static int  ParseRLE       ( decoder_t *, subpicture_t *, subpicture_data_t *);
00040 static void Render         ( decoder_t *, subpicture_t *, subpicture_data_t *);
00041 
00042 /*****************************************************************************
00043  * AddNibble: read a nibble from a source packet and add it to our integer.
00044  *****************************************************************************/
00045 static inline unsigned int AddNibble( unsigned int i_code,
00046                                       uint8_t *p_src, unsigned int *pi_index )
00047 {
00048     if( *pi_index & 0x1 )
00049     {
00050         return( i_code << 4 | ( p_src[(*pi_index)++ >> 1] & 0xf ) );
00051     }
00052     else
00053     {
00054         return( i_code << 4 | p_src[(*pi_index)++ >> 1] >> 4 );
00055     }
00056 }
00057 
00058 /*****************************************************************************
00059  * ParsePacket: parse an SPU packet and send it to the video output
00060  *****************************************************************************
00061  * This function parses the SPU packet and, if valid, sends it to the
00062  * video output.
00063  *****************************************************************************/
00064 subpicture_t * E_(ParsePacket)( decoder_t *p_dec )
00065 {
00066     decoder_sys_t *p_sys = p_dec->p_sys;
00067     subpicture_data_t *p_spu_data;
00068     subpicture_t *p_spu;
00069 
00070     /* Allocate the subpicture internal data. */
00071     p_spu = p_dec->pf_spu_buffer_new( p_dec );
00072     if( !p_spu ) return NULL;
00073 
00074     /* Rationale for the "p_spudec->i_rle_size * 4": we are going to
00075      * expand the RLE stuff so that we won't need to read nibbles later
00076      * on. This will speed things up a lot. Plus, we'll only need to do
00077      * this stupid interlacing stuff once. */
00078     p_spu_data = malloc( sizeof(subpicture_data_t) + 4 * p_sys->i_rle_size );
00079     p_spu_data->p_data = (uint8_t *)p_spu_data + sizeof(subpicture_data_t);
00080     p_spu_data->b_palette = VLC_FALSE;
00081     p_spu_data->b_auto_crop = VLC_FALSE;
00082     p_spu_data->i_y_top_offset = 0;
00083     p_spu_data->i_y_bottom_offset = 0;
00084 
00085     p_spu_data->pi_alpha[0] = 0x00;
00086     p_spu_data->pi_alpha[1] = 0x0f;
00087     p_spu_data->pi_alpha[2] = 0x0f;
00088     p_spu_data->pi_alpha[3] = 0x0f;
00089 
00090     /* Get display time now. If we do it later, we may miss the PTS. */
00091     p_spu_data->i_pts = p_sys->i_pts;
00092 
00093     p_spu->i_original_picture_width =
00094         p_dec->fmt_in.subs.spu.i_original_frame_width;
00095     p_spu->i_original_picture_height =
00096         p_dec->fmt_in.subs.spu.i_original_frame_height;
00097 
00098     /* Getting the control part */
00099     if( ParseControlSeq( p_dec, p_spu, p_spu_data ) )
00100     {
00101         /* There was a parse error, delete the subpicture */
00102         p_dec->pf_spu_buffer_del( p_dec, p_spu );
00103         return NULL;
00104     }
00105 
00106     /* We try to display it */
00107     if( ParseRLE( p_dec, p_spu, p_spu_data ) )
00108     {
00109         /* There was a parse error, delete the subpicture */
00110         p_dec->pf_spu_buffer_del( p_dec, p_spu );
00111         return NULL;
00112     }
00113 
00114     msg_Dbg( p_dec, "total size: 0x%x, RLE offsets: 0x%x 0x%x",
00115              p_sys->i_spu_size,
00116              p_spu_data->pi_offset[0], p_spu_data->pi_offset[1] );
00117 
00118     Render( p_dec, p_spu, p_spu_data );
00119     free( p_spu_data );
00120 
00121     return p_spu;
00122 }
00123 
00124 /*****************************************************************************
00125  * ParseControlSeq: parse all SPU control sequences
00126  *****************************************************************************
00127  * This is the most important part in SPU decoding. We get dates, palette
00128  * information, coordinates, and so on. For more information on the
00129  * subtitles format, see http://sam.zoy.org/doc/dvd/subtitles/index.html
00130  *****************************************************************************/
00131 static int ParseControlSeq( decoder_t *p_dec, subpicture_t *p_spu,
00132                             subpicture_data_t *p_spu_data )
00133 {
00134     decoder_sys_t *p_sys = p_dec->p_sys;
00135 
00136     /* Our current index in the SPU packet */
00137     unsigned int i_index = p_sys->i_rle_size + 4;
00138 
00139     /* The next start-of-control-sequence index and the previous one */
00140     unsigned int i_next_seq = 0, i_cur_seq = 0;
00141 
00142     /* Command and date */
00143     uint8_t i_command = SPU_CMD_END;
00144     mtime_t date = 0;
00145 
00146     unsigned int i, pi_alpha[4];
00147 
00148     /* Initialize the structure */
00149     p_spu->i_start = p_spu->i_stop = 0;
00150     p_spu->b_ephemer = VLC_FALSE;
00151 
00152     do
00153     {
00154         if( (int)i_index >= p_sys->i_spu_size + 1 )
00155         {
00156             /* sanity
00157              * XXX only on test by loop as p_sys->buffer is bigger than needed
00158              * to avoid checking at each access
00159              */
00160             break;
00161         }
00162 
00163         /* If we just read a command sequence, read the next one;
00164          * otherwise, go on with the commands of the current sequence. */
00165         if( i_command == SPU_CMD_END )
00166         {
00167             /* Get the control sequence date */
00168             date = (mtime_t)GetWBE( &p_sys->buffer[i_index] ) * 11000;
00169             /* FIXME How to access i_rate
00170                     * p_spudec->bit_stream.p_pes->i_rate / DEFAULT_RATE;
00171             */
00172 
00173             /* Next offset */
00174             i_cur_seq = i_index;
00175             i_next_seq = GetWBE( &p_sys->buffer[i_index+2] );
00176 
00177             /* Skip what we just read */
00178             i_index += 4;
00179         }
00180 
00181         i_command = p_sys->buffer[i_index++];
00182 
00183         switch( i_command )
00184         {
00185         case SPU_CMD_FORCE_DISPLAY: /* 00 (force displaying) */
00186             p_spu->i_start = p_spu_data->i_pts + date;
00187             p_spu->b_ephemer = VLC_TRUE;
00188             break;
00189 
00190         /* Convert the dates in seconds to PTS values */
00191         case SPU_CMD_START_DISPLAY: /* 01 (start displaying) */
00192             p_spu->i_start = p_spu_data->i_pts + date;
00193             break;
00194 
00195         case SPU_CMD_STOP_DISPLAY: /* 02 (stop displaying) */
00196             p_spu->i_stop = p_spu_data->i_pts + date;
00197             break;
00198 
00199         case SPU_CMD_SET_PALETTE:
00200 
00201             /* 03xxxx (palette) */
00202             if( p_dec->fmt_in.subs.spu.palette[0] == 0xBeeF )
00203             {
00204                 unsigned int idx[4];
00205 
00206                 p_spu_data->b_palette = VLC_TRUE;
00207 
00208                 idx[0] = (p_sys->buffer[i_index+0]>>4)&0x0f;
00209                 idx[1] = (p_sys->buffer[i_index+0])&0x0f;
00210                 idx[2] = (p_sys->buffer[i_index+1]>>4)&0x0f;
00211                 idx[3] = (p_sys->buffer[i_index+1])&0x0f;
00212 
00213                 for( i = 0; i < 4 ; i++ )
00214                 {
00215                     uint32_t i_color = p_dec->fmt_in.subs.spu.palette[1+idx[i]];
00216 
00217                     /* FIXME: this job should be done sooner */
00218                     p_spu_data->pi_yuv[3-i][0] = (i_color>>16) & 0xff;
00219                     p_spu_data->pi_yuv[3-i][1] = (i_color>>0) & 0xff;
00220                     p_spu_data->pi_yuv[3-i][2] = (i_color>>8) & 0xff;
00221                 }
00222             }
00223             i_index += 2;
00224 
00225             break;
00226 
00227         case SPU_CMD_SET_ALPHACHANNEL: /* 04xxxx (alpha channel) */
00228             pi_alpha[3] = (p_sys->buffer[i_index+0]>>4)&0x0f;
00229             pi_alpha[2] = (p_sys->buffer[i_index+0])&0x0f;
00230             pi_alpha[1] = (p_sys->buffer[i_index+1]>>4)&0x0f;
00231             pi_alpha[0] = (p_sys->buffer[i_index+1])&0x0f;
00232 
00233             /* Ignore blank alpha palette. Sometimes spurious blank
00234              * alpha palettes are present - dunno why. */
00235             if( pi_alpha[0] | pi_alpha[1] | pi_alpha[2] | pi_alpha[3] )
00236             {
00237                 p_spu_data->pi_alpha[0] = pi_alpha[0];
00238                 p_spu_data->pi_alpha[1] = pi_alpha[1];
00239                 p_spu_data->pi_alpha[2] = pi_alpha[2];
00240                 p_spu_data->pi_alpha[3] = pi_alpha[3];
00241             }
00242             else
00243             {
00244                 msg_Warn( p_dec, "ignoring blank alpha palette" );
00245             }
00246 
00247             i_index += 2;
00248             break;
00249 
00250         case SPU_CMD_SET_COORDINATES: /* 05xxxyyyxxxyyy (coordinates) */
00251             p_spu->i_x = (p_sys->buffer[i_index+0]<<4)|
00252                          ((p_sys->buffer[i_index+1]>>4)&0x0f);
00253             p_spu->i_width = (((p_sys->buffer[i_index+1]&0x0f)<<8)|
00254                               p_sys->buffer[i_index+2]) - p_spu->i_x + 1;
00255 
00256             p_spu->i_y = (p_sys->buffer[i_index+3]<<4)|
00257                          ((p_sys->buffer[i_index+4]>>4)&0x0f);
00258             p_spu->i_height = (((p_sys->buffer[i_index+4]&0x0f)<<8)|
00259                               p_sys->buffer[i_index+5]) - p_spu->i_y + 1;
00260 
00261             /* Auto crop fullscreen subtitles */
00262             if( p_spu->i_height > 250 )
00263                 p_spu_data->b_auto_crop = VLC_TRUE;
00264 
00265             i_index += 6;
00266             break;
00267 
00268         case SPU_CMD_SET_OFFSETS: /* 06xxxxyyyy (byte offsets) */
00269             p_spu_data->pi_offset[0] = GetWBE(&p_sys->buffer[i_index+0]) - 4;
00270             p_spu_data->pi_offset[1] = GetWBE(&p_sys->buffer[i_index+2]) - 4;
00271             i_index += 4;
00272             break;
00273 
00274         case SPU_CMD_END: /* ff (end) */
00275             break;
00276 
00277         default: /* xx (unknown command) */
00278             msg_Warn( p_dec, "unknown command 0x%.2x", i_command );
00279             return VLC_EGENERIC;
00280         }
00281 
00282         /* We need to check for quit commands here */
00283         if( p_dec->b_die )
00284         {
00285             return VLC_EGENERIC;
00286         }
00287 
00288     } while( i_command != SPU_CMD_END || i_index == i_next_seq );
00289 
00290     /* Check that the next sequence index matches the current one */
00291     if( i_next_seq != i_cur_seq )
00292     {
00293         msg_Err( p_dec, "index mismatch (0x%.4x != 0x%.4x)",
00294                  i_next_seq, i_cur_seq );
00295         return VLC_EGENERIC;
00296     }
00297 
00298     if( (int)i_index > p_sys->i_spu_size )
00299     {
00300         msg_Err( p_dec, "uh-oh, we went too far (0x%.4x > 0x%.4x)",
00301                  i_index, p_sys->i_spu_size );
00302         return VLC_EGENERIC;
00303     }
00304 
00305     if( !p_spu->i_start )
00306     {
00307         msg_Err( p_dec, "no `start display' command" );
00308     }
00309 
00310     if( p_spu->i_stop <= p_spu->i_start && !p_spu->b_ephemer )
00311     {
00312         /* This subtitle will live for 5 seconds or until the next subtitle */
00313         p_spu->i_stop = p_spu->i_start + (mtime_t)500 * 11000;
00314         p_spu->b_ephemer = VLC_TRUE;
00315     }
00316 
00317     /* Get rid of padding bytes */
00318     if( p_sys->i_spu_size > (int)i_index + 1 )
00319     {
00320         /* Zero or one padding byte, are quite usual
00321          * More than one padding byte - this is very strange, but
00322          * we can deal with it */
00323         msg_Warn( p_dec, "%i padding bytes, we usually get 0 or 1 of them",
00324                   p_sys->i_spu_size - i_index );
00325     }
00326 
00327     /* Successfully parsed ! */
00328     return VLC_SUCCESS;
00329 }
00330 
00331 /*****************************************************************************
00332  * ParseRLE: parse the RLE part of the subtitle
00333  *****************************************************************************
00334  * This part parses the subtitle graphical data and stores it in a more
00335  * convenient structure for later decoding. For more information on the
00336  * subtitles format, see http://sam.zoy.org/doc/dvd/subtitles/index.html
00337  *****************************************************************************/
00338 static int ParseRLE( decoder_t *p_dec, subpicture_t * p_spu,
00339                      subpicture_data_t *p_spu_data )
00340 {
00341     decoder_sys_t *p_sys = p_dec->p_sys;
00342     uint8_t       *p_src = &p_sys->buffer[4];
00343 
00344     unsigned int i_code;
00345 
00346     unsigned int i_width = p_spu->i_width;
00347     unsigned int i_height = p_spu->i_height;
00348     unsigned int i_x, i_y;
00349 
00350     uint16_t *p_dest = (uint16_t *)p_spu_data->p_data;
00351 
00352     /* The subtitles are interlaced, we need two offsets */
00353     unsigned int  i_id = 0;                   /* Start on the even SPU layer */
00354     unsigned int  pi_table[ 2 ];
00355     unsigned int *pi_offset;
00356 
00357     /* Cropping */
00358     vlc_bool_t b_empty_top = VLC_TRUE;
00359     unsigned int i_skipped_top = 0, i_skipped_bottom = 0;
00360     unsigned int i_transparent_code = 0;
00361  
00362     /* Colormap statistics */
00363     int i_border = -1;
00364     int stats[4]; stats[0] = stats[1] = stats[2] = stats[3] = 0;
00365 
00366     pi_table[ 0 ] = p_spu_data->pi_offset[ 0 ] << 1;
00367     pi_table[ 1 ] = p_spu_data->pi_offset[ 1 ] << 1;
00368 
00369     for( i_y = 0 ; i_y < i_height ; i_y++ )
00370     {
00371         pi_offset = pi_table + i_id;
00372 
00373         for( i_x = 0 ; i_x < i_width ; i_x += i_code >> 2 )
00374         {
00375             i_code = AddNibble( 0, p_src, pi_offset );
00376 
00377             if( i_code < 0x04 )
00378             {
00379                 i_code = AddNibble( i_code, p_src, pi_offset );
00380 
00381                 if( i_code < 0x10 )
00382                 {
00383                     i_code = AddNibble( i_code, p_src, pi_offset );
00384 
00385                     if( i_code < 0x040 )
00386                     {
00387                         i_code = AddNibble( i_code, p_src, pi_offset );
00388 
00389                         if( i_code < 0x0100 )
00390                         {
00391                             /* If the 14 first bits are set to 0, then it's a
00392                              * new line. We emulate it. */
00393                             if( i_code < 0x0004 )
00394                             {
00395                                 i_code |= ( i_width - i_x ) << 2;
00396                             }
00397                             else
00398                             {
00399                                 /* We have a boo boo ! */
00400                                 msg_Err( p_dec, "unknown RLE code "
00401                                          "0x%.4x", i_code );
00402                                 return VLC_EGENERIC;
00403                             }
00404                         }
00405                     }
00406                 }
00407             }
00408 
00409             if( ( (i_code >> 2) + i_x + i_y * i_width ) > i_height * i_width )
00410             {
00411                 msg_Err( p_dec, "out of bounds, %i at (%i,%i) is out of %ix%i",
00412                          i_code >> 2, i_x, i_y, i_width, i_height );
00413                 return VLC_EGENERIC;
00414             }
00415 
00416             /* Try to find the border color */
00417             if( p_spu_data->pi_alpha[ i_code & 0x3 ] != 0x00 )
00418             {
00419                 i_border = i_code & 0x3;
00420                 stats[i_border] += i_code >> 2;
00421             }
00422 
00423             /* Auto crop subtitles (a lot more optimized) */
00424             if( p_spu_data->b_auto_crop )
00425             {
00426                 if( !i_y )
00427                 {
00428                     /* We assume that if the first line is transparent, then
00429                      * it is using the palette index for the
00430                      * (background) transparent color */
00431                     if( (i_code >> 2) == i_width &&
00432                         p_spu_data->pi_alpha[ i_code & 0x3 ] == 0x00 )
00433                     {
00434                         i_transparent_code = i_code;
00435                     }
00436                     else
00437                     {
00438                         p_spu_data->b_auto_crop = VLC_FALSE;
00439                     }
00440                 }
00441 
00442                 if( i_code == i_transparent_code )
00443                 {
00444                     if( b_empty_top )
00445                     {
00446                         /* This is a blank top line, we skip it */
00447                       i_skipped_top++;
00448                     }
00449                     else
00450                     {
00451                         /* We can't be sure the current lines will be skipped,
00452                          * so we store the code just in case. */
00453                       *p_dest++ = i_code;
00454                       i_skipped_bottom++;
00455                     }
00456                 }
00457                 else
00458                 {
00459                     /* We got a valid code, store it */
00460                     *p_dest++ = i_code;
00461 
00462                     /* Valid code means no blank line */
00463                     b_empty_top = VLC_FALSE;
00464                     i_skipped_bottom = 0;
00465                 }
00466             }
00467             else
00468             {
00469                 *p_dest++ = i_code;
00470             }
00471         }
00472 
00473         /* Check that we didn't go too far */
00474         if( i_x > i_width )
00475         {
00476             msg_Err( p_dec, "i_x overflowed, %i > %i", i_x, i_width );
00477             return VLC_EGENERIC;
00478         }
00479 
00480         /* Byte-align the stream */
00481         if( *pi_offset & 0x1 )
00482         {
00483             (*pi_offset)++;
00484         }
00485 
00486         /* Swap fields */
00487         i_id = ~i_id & 0x1;
00488     }
00489 
00490     /* We shouldn't get any padding bytes */
00491     if( i_y < i_height )
00492     {
00493         msg_Err( p_dec, "padding bytes found in RLE sequence" );
00494         msg_Err( p_dec, "send mail to <[email protected]> if you "
00495                         "want to help debugging this" );
00496 
00497         /* Skip them just in case */
00498         while( i_y < i_height )
00499         {
00500             *p_dest++ = i_width << 2;
00501             i_y++;
00502         }
00503 
00504         return VLC_EGENERIC;
00505     }
00506 
00507     msg_Dbg( p_dec, "valid subtitle, size: %ix%i, position: %i,%i",
00508              p_spu->i_width, p_spu->i_height, p_spu->i_x, p_spu->i_y );
00509 
00510     /* Crop if necessary */
00511     if( i_skipped_top || i_skipped_bottom )
00512     {
00513         int i_y = p_spu->i_y + i_skipped_top;
00514         int i_height = p_spu->i_height - (i_skipped_top + i_skipped_bottom);
00515 
00516         p_spu_data->i_y_top_offset = i_skipped_top;
00517         p_spu_data->i_y_bottom_offset = i_skipped_bottom;
00518         msg_Dbg( p_dec, "cropped to: %ix%i, position: %i,%i",
00519                  p_spu->i_width, i_height, p_spu->i_x, i_y );
00520     }
00521  
00522     /* Handle color if no palette was found */
00523     if( !p_spu_data->b_palette )
00524     {
00525         int i, i_inner = -1, i_shade = -1;
00526 
00527         /* Set the border color */
00528         p_spu_data->pi_yuv[i_border][0] = 0x00;
00529         p_spu_data->pi_yuv[i_border][1] = 0x80;
00530         p_spu_data->pi_yuv[i_border][2] = 0x80;
00531         stats[i_border] = 0;
00532 
00533         /* Find the inner colors */
00534         for( i = 0 ; i < 4 && i_inner == -1 ; i++ )
00535         {
00536             if( stats[i] )
00537             {
00538                 i_inner = i;
00539             }
00540         }
00541 
00542         for(       ; i < 4 && i_shade == -1 ; i++ )
00543         {
00544             if( stats[i] )
00545             {
00546                 if( stats[i] > stats[i_inner] )
00547                 {
00548                     i_shade = i_inner;
00549                     i_inner = i;
00550                 }
00551                 else
00552                 {
00553                     i_shade = i;
00554                 }
00555             }
00556         }
00557 
00558         /* Set the inner color */
00559         if( i_inner != -1 )
00560         {
00561             p_spu_data->pi_yuv[i_inner][0] = 0xff;
00562             p_spu_data->pi_yuv[i_inner][1] = 0x80;
00563             p_spu_data->pi_yuv[i_inner][2] = 0x80;
00564         }
00565 
00566         /* Set the anti-aliasing color */
00567         if( i_shade != -1 )
00568         {
00569             p_spu_data->pi_yuv[i_shade][0] = 0x80;
00570             p_spu_data->pi_yuv[i_shade][1] = 0x80;
00571             p_spu_data->pi_yuv[i_shade][2] = 0x80;
00572         }
00573 
00574         msg_Dbg( p_dec, "using custom palette (border %i, inner %i, shade %i)",
00575                  i_border, i_inner, i_shade );
00576     }
00577 
00578     return VLC_SUCCESS;
00579 }
00580 
00581 static void Render( decoder_t *p_dec, subpicture_t *p_spu,
00582                     subpicture_data_t *p_spu_data )
00583 {
00584     uint8_t *p_p;
00585     int i_x, i_y, i_len, i_color, i_pitch;
00586     uint16_t *p_source = (uint16_t *)p_spu_data->p_data;
00587     video_format_t fmt;
00588 
00589     /* Create a new subpicture region */
00590     memset( &fmt, 0, sizeof(video_format_t) );
00591     fmt.i_chroma = VLC_FOURCC('Y','U','V','P');
00592     fmt.i_aspect = 0; /* 0 means use aspect ratio of background video */
00593     fmt.i_width = fmt.i_visible_width = p_spu->i_width;
00594     fmt.i_height = fmt.i_visible_height = p_spu->i_height -
00595         p_spu_data->i_y_top_offset - p_spu_data->i_y_bottom_offset;
00596     fmt.i_x_offset = fmt.i_y_offset = 0;
00597     p_spu->p_region = p_spu->pf_create_region( VLC_OBJECT(p_dec), &fmt );
00598     if( !p_spu->p_region )
00599     {
00600         msg_Err( p_dec, "cannot allocate SPU region" );
00601         return;
00602     }
00603 
00604     p_spu->p_region->i_x = 0;
00605     p_spu->p_region->i_y = p_spu_data->i_y_top_offset;
00606     p_p = p_spu->p_region->picture.p->p_pixels;
00607     i_pitch = p_spu->p_region->picture.p->i_pitch;
00608 
00609     /* Build palette */
00610     fmt.p_palette->i_entries = 4;
00611     for( i_x = 0; i_x < fmt.p_palette->i_entries; i_x++ )
00612     {
00613         fmt.p_palette->palette[i_x][0] = p_spu_data->pi_yuv[i_x][0];
00614         fmt.p_palette->palette[i_x][1] = p_spu_data->pi_yuv[i_x][1];
00615         fmt.p_palette->palette[i_x][2] = p_spu_data->pi_yuv[i_x][2];
00616         fmt.p_palette->palette[i_x][3] =
00617             p_spu_data->pi_alpha[i_x] == 0xf ? 0xff :
00618             p_spu_data->pi_alpha[i_x] << 4;
00619     }
00620 
00621     /* Draw until we reach the bottom of the subtitle */
00622     for( i_y = 0; i_y < (int)fmt.i_height * i_pitch; i_y += i_pitch )
00623     {
00624         /* Draw until we reach the end of the line */
00625         for( i_x = 0 ; i_x < (int)fmt.i_width; i_x += i_len )
00626         {
00627             /* Get the RLE part, then draw the line */
00628             i_color = *p_source & 0x3;
00629             i_len = *p_source++ >> 2;
00630             memset( p_p + i_x + i_y, i_color, i_len );
00631         }
00632     }
00633 }

Generated on Tue Dec 20 10:14:30 2005 for vlc-0.8.4a by  doxygen 1.4.2