parse.c
上传用户:riyaled888
上传日期:2009-03-27
资源大小:7338k
文件大小:22k
源码类别:

多媒体

开发平台:

MultiPlatform

  1. /*****************************************************************************
  2.  * parse.c: SPU parser
  3.  *****************************************************************************
  4.  * Copyright (C) 2000-2001 VideoLAN
  5.  * $Id: parse.c 8758 2004-09-21 20:33:59Z gbazin $
  6.  *
  7.  * Authors: Samuel Hocevar <sam@zoy.org>
  8.  *          Laurent Aimar <fenrir@via.ecp.fr>
  9.  *          Gildas Bazin <gbazin@videolan.org>
  10.  *
  11.  * This program is free software; you can redistribute it and/or modify
  12.  * it under the terms of the GNU General Public License as published by
  13.  * the Free Software Foundation; either version 2 of the License, or
  14.  * (at your option) any later version.
  15.  *
  16.  * This program is distributed in the hope that it will be useful,
  17.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  19.  * GNU General Public License for more details.
  20.  *
  21.  * You should have received a copy of the GNU General Public License
  22.  * along with this program; if not, write to the Free Software
  23.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
  24.  *****************************************************************************/
  25. /*****************************************************************************
  26.  * Preamble
  27.  *****************************************************************************/
  28. #include <vlc/vlc.h>
  29. #include <vlc/vout.h>
  30. #include <vlc/decoder.h>
  31. #include "spudec.h"
  32. /*****************************************************************************
  33.  * Local prototypes.
  34.  *****************************************************************************/
  35. static int  ParseControlSeq( decoder_t *, subpicture_t *, subpicture_data_t *);
  36. static int  ParseRLE       ( decoder_t *, subpicture_t *, subpicture_data_t *);
  37. static void Render         ( decoder_t *, subpicture_t *, subpicture_data_t *);
  38. /*****************************************************************************
  39.  * AddNibble: read a nibble from a source packet and add it to our integer.
  40.  *****************************************************************************/
  41. static inline unsigned int AddNibble( unsigned int i_code,
  42.                                       uint8_t *p_src, int *pi_index )
  43. {
  44.     if( *pi_index & 0x1 )
  45.     {
  46.         return( i_code << 4 | ( p_src[(*pi_index)++ >> 1] & 0xf ) );
  47.     }
  48.     else
  49.     {
  50.         return( i_code << 4 | p_src[(*pi_index)++ >> 1] >> 4 );
  51.     }
  52. }
  53. /*****************************************************************************
  54.  * ParsePacket: parse an SPU packet and send it to the video output
  55.  *****************************************************************************
  56.  * This function parses the SPU packet and, if valid, sends it to the
  57.  * video output.
  58.  *****************************************************************************/
  59. subpicture_t * E_(ParsePacket)( decoder_t *p_dec )
  60. {
  61.     decoder_sys_t *p_sys = p_dec->p_sys;
  62.     subpicture_data_t *p_spu_data;
  63.     subpicture_t *p_spu;
  64.     /* Allocate the subpicture internal data. */
  65.     p_spu = p_dec->pf_spu_buffer_new( p_dec );
  66.     if( !p_spu ) return NULL;
  67.     /* Rationale for the "p_spudec->i_rle_size * 4": we are going to
  68.      * expand the RLE stuff so that we won't need to read nibbles later
  69.      * on. This will speed things up a lot. Plus, we'll only need to do
  70.      * this stupid interlacing stuff once. */
  71.     p_spu_data = malloc( sizeof(subpicture_data_t) + 4 * p_sys->i_rle_size );
  72.     p_spu_data->p_data = (uint8_t *)p_spu_data + sizeof(subpicture_data_t);
  73.     p_spu_data->b_palette = VLC_FALSE;
  74.     p_spu_data->b_auto_crop = VLC_FALSE;
  75.     p_spu_data->i_y_top_offset = 0;
  76.     p_spu_data->i_y_bottom_offset = 0;
  77.     p_spu_data->pi_alpha[0] = 0x00;
  78.     p_spu_data->pi_alpha[1] = 0x0f;
  79.     p_spu_data->pi_alpha[2] = 0x0f;
  80.     p_spu_data->pi_alpha[3] = 0x0f;
  81.     /* Get display time now. If we do it later, we may miss the PTS. */
  82.     p_spu_data->i_pts = p_sys->i_pts;
  83.     p_spu->i_original_picture_width =
  84.         p_dec->fmt_in.subs.spu.i_original_frame_width;
  85.     p_spu->i_original_picture_height =
  86.         p_dec->fmt_in.subs.spu.i_original_frame_height;
  87.     /* Getting the control part */
  88.     if( ParseControlSeq( p_dec, p_spu, p_spu_data ) )
  89.     {
  90.         /* There was a parse error, delete the subpicture */
  91.         p_dec->pf_spu_buffer_del( p_dec, p_spu );
  92.         return NULL;
  93.     }
  94.     /* We try to display it */
  95.     if( ParseRLE( p_dec, p_spu, p_spu_data ) )
  96.     {
  97.         /* There was a parse error, delete the subpicture */
  98.         p_dec->pf_spu_buffer_del( p_dec, p_spu );
  99.         return NULL;
  100.     }
  101.     msg_Dbg( p_dec, "total size: 0x%x, RLE offsets: 0x%x 0x%x",
  102.              p_sys->i_spu_size,
  103.              p_spu_data->pi_offset[0], p_spu_data->pi_offset[1] );
  104.     Render( p_dec, p_spu, p_spu_data );
  105.     free( p_spu_data );
  106.     return p_spu;
  107. }
  108. /*****************************************************************************
  109.  * ParseControlSeq: parse all SPU control sequences
  110.  *****************************************************************************
  111.  * This is the most important part in SPU decoding. We get dates, palette
  112.  * information, coordinates, and so on. For more information on the
  113.  * subtitles format, see http://sam.zoy.org/doc/dvd/subtitles/index.html
  114.  *****************************************************************************/
  115. static int ParseControlSeq( decoder_t *p_dec, subpicture_t *p_spu,
  116.                             subpicture_data_t *p_spu_data )
  117. {
  118.     decoder_sys_t *p_sys = p_dec->p_sys;
  119.     /* Our current index in the SPU packet */
  120.     unsigned int i_index = p_sys->i_rle_size + 4;
  121.     /* The next start-of-control-sequence index and the previous one */
  122.     unsigned int i_next_seq = 0, i_cur_seq = 0;
  123.     /* Command and date */
  124.     uint8_t i_command = SPU_CMD_END;
  125.     mtime_t date = 0;
  126.     unsigned int i, pi_alpha[4];
  127.     /* Initialize the structure */
  128.     p_spu->i_start = p_spu->i_stop = 0;
  129.     p_spu->b_ephemer = VLC_FALSE;
  130.     do
  131.     {
  132.         if( (int)i_index >= p_sys->i_spu_size + 1 )
  133.         {
  134.             /* sanity
  135.              * XXX only on test by loop as p_sys->buffer is bigger than needed
  136.              * to avoid checking at each access
  137.              */
  138.             break;
  139.         }
  140.         /* If we just read a command sequence, read the next one;
  141.          * otherwise, go on with the commands of the current sequence. */
  142.         if( i_command == SPU_CMD_END )
  143.         {
  144.             /* Get the control sequence date */
  145.             date = (mtime_t)GetWBE( &p_sys->buffer[i_index] ) * 11000;
  146.             /* FIXME How to access i_rate
  147.                     * p_spudec->bit_stream.p_pes->i_rate / DEFAULT_RATE;
  148.             */
  149.             /* Next offset */
  150.             i_cur_seq = i_index;
  151.             i_next_seq = GetWBE( &p_sys->buffer[i_index+2] );
  152.             /* Skip what we just read */
  153.             i_index += 4;
  154.         }
  155.         i_command = p_sys->buffer[i_index++];
  156.         switch( i_command )
  157.         {
  158.         case SPU_CMD_FORCE_DISPLAY: /* 00 (force displaying) */
  159.             p_spu->i_start = p_spu_data->i_pts + date;
  160.             p_spu->b_ephemer = VLC_TRUE;
  161.             break;
  162.         /* Convert the dates in seconds to PTS values */
  163.         case SPU_CMD_START_DISPLAY: /* 01 (start displaying) */
  164.             p_spu->i_start = p_spu_data->i_pts + date;
  165.             break;
  166.         case SPU_CMD_STOP_DISPLAY: /* 02 (stop displaying) */
  167.             p_spu->i_stop = p_spu_data->i_pts + date;
  168.             break;
  169.         case SPU_CMD_SET_PALETTE:
  170.             /* 03xxxx (palette) */
  171.             if( p_dec->fmt_in.subs.spu.palette[0] == 0xBeeF )
  172.             {
  173.                 unsigned int idx[4];
  174.                 p_spu_data->b_palette = VLC_TRUE;
  175.                 idx[0] = (p_sys->buffer[i_index+0]>>4)&0x0f;
  176.                 idx[1] = (p_sys->buffer[i_index+0])&0x0f;
  177.                 idx[2] = (p_sys->buffer[i_index+1]>>4)&0x0f;
  178.                 idx[3] = (p_sys->buffer[i_index+1])&0x0f;
  179.                 for( i = 0; i < 4 ; i++ )
  180.                 {
  181.                     uint32_t i_color = p_dec->fmt_in.subs.spu.palette[1+idx[i]];
  182.                     /* FIXME: this job should be done sooner */
  183.                     p_spu_data->pi_yuv[3-i][0] = (i_color>>16) & 0xff;
  184.                     p_spu_data->pi_yuv[3-i][1] = (i_color>>0) & 0xff;
  185.                     p_spu_data->pi_yuv[3-i][2] = (i_color>>8) & 0xff;
  186.                 }
  187.             }
  188.             i_index += 2;
  189.             break;
  190.         case SPU_CMD_SET_ALPHACHANNEL: /* 04xxxx (alpha channel) */
  191.             pi_alpha[3] = (p_sys->buffer[i_index+0]>>4)&0x0f;
  192.             pi_alpha[2] = (p_sys->buffer[i_index+0])&0x0f;
  193.             pi_alpha[1] = (p_sys->buffer[i_index+1]>>4)&0x0f;
  194.             pi_alpha[0] = (p_sys->buffer[i_index+1])&0x0f;
  195.             /* Ignore blank alpha palette. Sometimes spurious blank
  196.              * alpha palettes are present - dunno why. */
  197.             if( pi_alpha[0] | pi_alpha[1] | pi_alpha[2] | pi_alpha[3] )
  198.             {
  199.                 p_spu_data->pi_alpha[0] = pi_alpha[0];
  200.                 p_spu_data->pi_alpha[1] = pi_alpha[1];
  201.                 p_spu_data->pi_alpha[2] = pi_alpha[2];
  202.                 p_spu_data->pi_alpha[3] = pi_alpha[3];
  203.             }
  204.             else
  205.             {
  206.                 msg_Warn( p_dec, "ignoring blank alpha palette" );
  207.             }
  208.             i_index += 2;
  209.             break;
  210.         case SPU_CMD_SET_COORDINATES: /* 05xxxyyyxxxyyy (coordinates) */
  211.             p_spu->i_x = (p_sys->buffer[i_index+0]<<4)|
  212.                          ((p_sys->buffer[i_index+1]>>4)&0x0f);
  213.             p_spu->i_width = (((p_sys->buffer[i_index+1]&0x0f)<<8)|
  214.                               p_sys->buffer[i_index+2]) - p_spu->i_x + 1;
  215.             p_spu->i_y = (p_sys->buffer[i_index+3]<<4)|
  216.                          ((p_sys->buffer[i_index+4]>>4)&0x0f);
  217.             p_spu->i_height = (((p_sys->buffer[i_index+4]&0x0f)<<8)|
  218.                               p_sys->buffer[i_index+5]) - p_spu->i_y + 1;
  219.             /* Auto crop fullscreen subtitles */
  220.             if( p_spu->i_height > 250 )
  221.                 p_spu_data->b_auto_crop = VLC_TRUE;
  222.             i_index += 6;
  223.             break;
  224.         case SPU_CMD_SET_OFFSETS: /* 06xxxxyyyy (byte offsets) */
  225.             p_spu_data->pi_offset[0] = GetWBE(&p_sys->buffer[i_index+0]) - 4;
  226.             p_spu_data->pi_offset[1] = GetWBE(&p_sys->buffer[i_index+2]) - 4;
  227.             i_index += 4;
  228.             break;
  229.         case SPU_CMD_END: /* ff (end) */
  230.             break;
  231.         default: /* xx (unknown command) */
  232.             msg_Warn( p_dec, "unknown command 0x%.2x", i_command );
  233.             return VLC_EGENERIC;
  234.         }
  235.         /* We need to check for quit commands here */
  236.         if( p_dec->b_die )
  237.         {
  238.             return VLC_EGENERIC;
  239.         }
  240.     } while( i_command != SPU_CMD_END || i_index == i_next_seq );
  241.     /* Check that the next sequence index matches the current one */
  242.     if( i_next_seq != i_cur_seq )
  243.     {
  244.         msg_Err( p_dec, "index mismatch (0x%.4x != 0x%.4x)",
  245.                  i_next_seq, i_cur_seq );
  246.         return VLC_EGENERIC;
  247.     }
  248.     if( (int)i_index > p_sys->i_spu_size )
  249.     {
  250.         msg_Err( p_dec, "uh-oh, we went too far (0x%.4x > 0x%.4x)",
  251.                  i_index, p_sys->i_spu_size );
  252.         return VLC_EGENERIC;
  253.     }
  254.     if( !p_spu->i_start )
  255.     {
  256.         msg_Err( p_dec, "no `start display' command" );
  257.     }
  258.     if( p_spu->i_stop <= p_spu->i_start && !p_spu->b_ephemer )
  259.     {
  260.         /* This subtitle will live for 5 seconds or until the next subtitle */
  261.         p_spu->i_stop = p_spu->i_start + (mtime_t)500 * 11000;
  262.         p_spu->b_ephemer = VLC_TRUE;
  263.     }
  264.     /* Get rid of padding bytes */
  265.     if( p_sys->i_spu_size > (int)i_index + 1 )
  266.     {
  267.         /* Zero or one padding byte, are quite usual
  268.          * More than one padding byte - this is very strange, but
  269.          * we can deal with it */
  270.         msg_Warn( p_dec, "%i padding bytes, we usually get 0 or 1 of them",
  271.                   p_sys->i_spu_size - i_index );
  272.     }
  273.     /* Successfully parsed ! */
  274.     return VLC_SUCCESS;
  275. }
  276. /*****************************************************************************
  277.  * ParseRLE: parse the RLE part of the subtitle
  278.  *****************************************************************************
  279.  * This part parses the subtitle graphical data and stores it in a more
  280.  * convenient structure for later decoding. For more information on the
  281.  * subtitles format, see http://sam.zoy.org/doc/dvd/subtitles/index.html
  282.  *****************************************************************************/
  283. static int ParseRLE( decoder_t *p_dec, subpicture_t * p_spu,
  284.                      subpicture_data_t *p_spu_data )
  285. {
  286.     decoder_sys_t *p_sys = p_dec->p_sys;
  287.     uint8_t       *p_src = &p_sys->buffer[4];
  288.     unsigned int i_code;
  289.     unsigned int i_width = p_spu->i_width;
  290.     unsigned int i_height = p_spu->i_height;
  291.     unsigned int i_x, i_y;
  292.     uint16_t *p_dest = (uint16_t *)p_spu_data->p_data;
  293.     /* The subtitles are interlaced, we need two offsets */
  294.     unsigned int  i_id = 0;                   /* Start on the even SPU layer */
  295.     unsigned int  pi_table[ 2 ];
  296.     unsigned int *pi_offset;
  297.     /* Cropping */
  298.     vlc_bool_t b_empty_top = VLC_TRUE;
  299.     unsigned int i_skipped_top = 0, i_skipped_bottom = 0;
  300.     unsigned int i_transparent_code = 0;
  301.  
  302.     /* Colormap statistics */
  303.     int i_border = -1;
  304.     int stats[4]; stats[0] = stats[1] = stats[2] = stats[3] = 0;
  305.     pi_table[ 0 ] = p_spu_data->pi_offset[ 0 ] << 1;
  306.     pi_table[ 1 ] = p_spu_data->pi_offset[ 1 ] << 1;
  307.     for( i_y = 0 ; i_y < i_height ; i_y++ )
  308.     {
  309.         pi_offset = pi_table + i_id;
  310.         for( i_x = 0 ; i_x < i_width ; i_x += i_code >> 2 )
  311.         {
  312.             i_code = AddNibble( 0, p_src, pi_offset );
  313.             if( i_code < 0x04 )
  314.             {
  315.                 i_code = AddNibble( i_code, p_src, pi_offset );
  316.                 if( i_code < 0x10 )
  317.                 {
  318.                     i_code = AddNibble( i_code, p_src, pi_offset );
  319.                     if( i_code < 0x040 )
  320.                     {
  321.                         i_code = AddNibble( i_code, p_src, pi_offset );
  322.                         if( i_code < 0x0100 )
  323.                         {
  324.                             /* If the 14 first bits are set to 0, then it's a
  325.                              * new line. We emulate it. */
  326.                             if( i_code < 0x0004 )
  327.                             {
  328.                                 i_code |= ( i_width - i_x ) << 2;
  329.                             }
  330.                             else
  331.                             {
  332.                                 /* We have a boo boo ! */
  333.                                 msg_Err( p_dec, "unknown RLE code "
  334.                                          "0x%.4x", i_code );
  335.                                 return VLC_EGENERIC;
  336.                             }
  337.                         }
  338.                     }
  339.                 }
  340.             }
  341.             if( ( (i_code >> 2) + i_x + i_y * i_width ) > i_height * i_width )
  342.             {
  343.                 msg_Err( p_dec, "out of bounds, %i at (%i,%i) is out of %ix%i",
  344.                          i_code >> 2, i_x, i_y, i_width, i_height );
  345.                 return VLC_EGENERIC;
  346.             }
  347.             /* Try to find the border color */
  348.             if( p_spu_data->pi_alpha[ i_code & 0x3 ] != 0x00 )
  349.             {
  350.                 i_border = i_code & 0x3;
  351.                 stats[i_border] += i_code >> 2;
  352.             }
  353.             /* Auto crop subtitles (a lot more optimized) */
  354.             if( p_spu_data->b_auto_crop )
  355.             {
  356.                 if( !i_y )
  357.                 {
  358.                     /* We assume that if the first line is transparent, then
  359.                      * it is using the palette index for the
  360.                      * (background) transparent color */
  361.                     if( (i_code >> 2) == i_width &&
  362.                         p_spu_data->pi_alpha[ i_code & 0x3 ] == 0x00 )
  363.                     {
  364.                         i_transparent_code = i_code;
  365.                     }
  366.                     else
  367.                     {
  368.                         p_spu_data->b_auto_crop = VLC_FALSE;
  369.                     }
  370.                 }
  371.                 if( i_code == i_transparent_code )
  372.                 {
  373.                     if( b_empty_top )
  374.                     {
  375.                         /* This is a blank top line, we skip it */
  376.                       i_skipped_top++;
  377.                     }
  378.                     else
  379.                     {
  380.                         /* We can't be sure the current lines will be skipped,
  381.                          * so we store the code just in case. */
  382.                       *p_dest++ = i_code;
  383.                       i_skipped_bottom++;
  384.                     }
  385.                 }
  386.                 else
  387.                 {
  388.                     /* We got a valid code, store it */
  389.                     *p_dest++ = i_code;
  390.                     /* Valid code means no blank line */
  391.                     b_empty_top = VLC_FALSE;
  392.                     i_skipped_bottom = 0;
  393.                 }
  394.             }
  395.             else
  396.             {
  397.                 *p_dest++ = i_code;
  398.             }
  399.         }
  400.         /* Check that we didn't go too far */
  401.         if( i_x > i_width )
  402.         {
  403.             msg_Err( p_dec, "i_x overflowed, %i > %i", i_x, i_width );
  404.             return VLC_EGENERIC;
  405.         }
  406.         /* Byte-align the stream */
  407.         if( *pi_offset & 0x1 )
  408.         {
  409.             (*pi_offset)++;
  410.         }
  411.         /* Swap fields */
  412.         i_id = ~i_id & 0x1;
  413.     }
  414.     /* We shouldn't get any padding bytes */
  415.     if( i_y < i_height )
  416.     {
  417.         msg_Err( p_dec, "padding bytes found in RLE sequence" );
  418.         msg_Err( p_dec, "send mail to <sam@zoy.org> if you "
  419.                         "want to help debugging this" );
  420.         /* Skip them just in case */
  421.         while( i_y < i_height )
  422.         {
  423.             *p_dest++ = i_width << 2;
  424.             i_y++;
  425.         }
  426.         return VLC_EGENERIC;
  427.     }
  428.     msg_Dbg( p_dec, "valid subtitle, size: %ix%i, position: %i,%i",
  429.              p_spu->i_width, p_spu->i_height, p_spu->i_x, p_spu->i_y );
  430.     /* Crop if necessary */
  431.     if( i_skipped_top || i_skipped_bottom )
  432.     {
  433.         int i_y = p_spu->i_y + i_skipped_top;
  434.         int i_height = p_spu->i_height - (i_skipped_top + i_skipped_bottom);
  435.         p_spu_data->i_y_top_offset = i_skipped_top;
  436.         p_spu_data->i_y_bottom_offset = i_skipped_bottom;
  437.         msg_Dbg( p_dec, "cropped to: %ix%i, position: %i,%i",
  438.                  p_spu->i_width, i_height, p_spu->i_x, i_y );
  439.     }
  440.  
  441.     /* Handle color if no palette was found */
  442.     if( !p_spu_data->b_palette )
  443.     {
  444.         int i, i_inner = -1, i_shade = -1;
  445.         /* Set the border color */
  446.         p_spu_data->pi_yuv[i_border][0] = 0x00;
  447.         p_spu_data->pi_yuv[i_border][1] = 0x80;
  448.         p_spu_data->pi_yuv[i_border][2] = 0x80;
  449.         stats[i_border] = 0;
  450.         /* Find the inner colors */
  451.         for( i = 0 ; i < 4 && i_inner == -1 ; i++ )
  452.         {
  453.             if( stats[i] )
  454.             {
  455.                 i_inner = i;
  456.             }
  457.         }
  458.         for(       ; i < 4 && i_shade == -1 ; i++ )
  459.         {
  460.             if( stats[i] )
  461.             {
  462.                 if( stats[i] > stats[i_inner] )
  463.                 {
  464.                     i_shade = i_inner;
  465.                     i_inner = i;
  466.                 }
  467.                 else
  468.                 {
  469.                     i_shade = i;
  470.                 }
  471.             }
  472.         }
  473.         /* Set the inner color */
  474.         if( i_inner != -1 )
  475.         {
  476.             p_spu_data->pi_yuv[i_inner][0] = 0xff;
  477.             p_spu_data->pi_yuv[i_inner][1] = 0x80;
  478.             p_spu_data->pi_yuv[i_inner][2] = 0x80;
  479.         }
  480.         /* Set the anti-aliasing color */
  481.         if( i_shade != -1 )
  482.         {
  483.             p_spu_data->pi_yuv[i_shade][0] = 0x80;
  484.             p_spu_data->pi_yuv[i_shade][1] = 0x80;
  485.             p_spu_data->pi_yuv[i_shade][2] = 0x80;
  486.         }
  487.         msg_Dbg( p_dec, "using custom palette (border %i, inner %i, shade %i)",
  488.                  i_border, i_inner, i_shade );
  489.     }
  490.     return VLC_SUCCESS;
  491. }
  492. static void Render( decoder_t *p_dec, subpicture_t *p_spu,
  493.                     subpicture_data_t *p_spu_data )
  494. {
  495.     uint8_t *p_p;
  496.     int i_x, i_y, i_len, i_color, i_pitch;
  497.     uint16_t *p_source = (uint16_t *)p_spu_data->p_data;
  498.     video_format_t fmt;
  499.     /* Create a new subpicture region */
  500.     memset( &fmt, 0, sizeof(video_format_t) );
  501.     fmt.i_chroma = VLC_FOURCC('Y','U','V','P');
  502.     fmt.i_aspect = VOUT_ASPECT_FACTOR;
  503.     fmt.i_width = fmt.i_visible_width = p_spu->i_width;
  504.     fmt.i_height = fmt.i_visible_height = p_spu->i_height -
  505.         p_spu_data->i_y_top_offset - p_spu_data->i_y_bottom_offset;
  506.     fmt.i_x_offset = fmt.i_y_offset = 0;
  507.     p_spu->p_region = p_spu->pf_create_region( VLC_OBJECT(p_dec), &fmt );
  508.     if( !p_spu->p_region )
  509.     {
  510.         msg_Err( p_dec, "cannot allocate SPU region" );
  511.         return;
  512.     }
  513.     p_spu->p_region->i_x = 0;
  514.     p_spu->p_region->i_y = p_spu_data->i_y_top_offset;
  515.     p_p = p_spu->p_region->picture.p->p_pixels;
  516.     i_pitch = p_spu->p_region->picture.p->i_pitch;
  517.     /* Build palette */
  518.     fmt.p_palette->i_entries = 4;
  519.     for( i_x = 0; i_x < fmt.p_palette->i_entries; i_x++ )
  520.     {
  521.         fmt.p_palette->palette[i_x][0] = p_spu_data->pi_yuv[i_x][0];
  522.         fmt.p_palette->palette[i_x][1] = p_spu_data->pi_yuv[i_x][1];
  523.         fmt.p_palette->palette[i_x][2] = p_spu_data->pi_yuv[i_x][2];
  524.         fmt.p_palette->palette[i_x][3] =
  525.             p_spu_data->pi_alpha[i_x] == 0xf ? 0xff :
  526.             p_spu_data->pi_alpha[i_x] << 4;
  527.     }
  528.     /* Draw until we reach the bottom of the subtitle */
  529.     for( i_y = 0; i_y < (int)fmt.i_height * i_pitch; i_y += i_pitch )
  530.     {
  531.         /* Draw until we reach the end of the line */
  532.         for( i_x = 0 ; i_x < (int)fmt.i_width; i_x += i_len )
  533.         {
  534.             /* Get the RLE part, then draw the line */
  535.             i_color = *p_source & 0x3;
  536.             i_len = *p_source++ >> 2;
  537.             memset( p_p + i_x + i_y, i_color, i_len );
  538.         }
  539.     }
  540. }