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

cvdsub.c

00001 /*****************************************************************************
00002  * cvd.c : CVD Subtitle decoder
00003  *****************************************************************************
00004  * Copyright (C) 2003, 2004 the VideoLAN team
00005  * $Id: cvdsub.c 11664 2005-07-09 06:17:09Z courmisch $
00006  *
00007  * Authors: Rocky Bernstein
00008  *          Gildas Bazin <[email protected]>
00009  *          Julio Sanchez Fernandez (http://subhandler.sourceforge.net)
00010  *          Laurent Aimar <[email protected]>
00011  *
00012  * This program is free software; you can redistribute it and/or modify
00013  * it under the terms of the GNU General Public License as published by
00014  * the Free Software Foundation; either version 2 of the License, or
00015  * (at your option) any later version.
00016  *
00017  * This program is distributed in the hope that it will be useful,
00018  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00019  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00020  * GNU General Public License for more details.
00021  *
00022  * You should have received a copy of the GNU General Public License
00023  * along with this program; if not, write to the Free Software
00024  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
00025  *****************************************************************************/
00026 
00027 /*****************************************************************************
00028  * Preamble
00029  *****************************************************************************/
00030 #include <vlc/vlc.h>
00031 #include <vlc/vout.h>
00032 #include <vlc/decoder.h>
00033 
00034 #include "vlc_bits.h"
00035 
00036 #define DEBUG_CVDSUB 1
00037 
00038 /*****************************************************************************
00039  * Module descriptor.
00040  *****************************************************************************/
00041 static int  DecoderOpen   ( vlc_object_t * );
00042 static int  PacketizerOpen( vlc_object_t * );
00043 static void DecoderClose  ( vlc_object_t * );
00044 
00045 vlc_module_begin();
00046     set_description( _("CVD subtitle decoder") );
00047     set_capability( "decoder", 50 );
00048     set_callbacks( DecoderOpen, DecoderClose );
00049 
00050     add_submodule();
00051     set_description( _("Chaoji VCD subtitle packetizer") );
00052     set_capability( "packetizer", 50 );
00053     set_callbacks( PacketizerOpen, DecoderClose );
00054 vlc_module_end();
00055 
00056 /*****************************************************************************
00057  * Local prototypes
00058  *****************************************************************************/
00059 static subpicture_t *Decode( decoder_t *, block_t ** );
00060 static block_t *Packetize  ( decoder_t *, block_t ** );
00061 static block_t *Reassemble ( decoder_t *, block_t * );
00062 static void ParseMetaInfo  ( decoder_t *, block_t * );
00063 static void ParseHeader    ( decoder_t *, block_t * );
00064 static subpicture_t *DecodePacket( decoder_t *, block_t * );
00065 static void RenderImage( decoder_t *, block_t *, subpicture_region_t * );
00066 
00067 #define SUBTITLE_BLOCK_EMPTY 0
00068 #define SUBTITLE_BLOCK_PARTIAL 1
00069 #define SUBTITLE_BLOCK_COMPLETE 2
00070 
00071 struct decoder_sys_t
00072 {
00073   int      b_packetizer;
00074 
00075   int      i_state;    /* data-gathering state for this subtitle */
00076 
00077   block_t  *p_spu;   /* Bytes of the packet. */
00078 
00079   int     i_spu_size;     /* goal for subtitle_data_pos while gathering,
00080                              size of used subtitle_data later */
00081 
00082   uint16_t i_image_offset;      /* offset from subtitle_data to compressed
00083                                    image data */
00084   int i_image_length;           /* size of the compressed image data */
00085   int first_field_offset;       /* offset of even raster lines */
00086   int second_field_offset;      /* offset of odd raster lines */
00087   int metadata_offset;          /* offset to data describing the image */
00088   int metadata_length;          /* length of metadata */
00089 
00090   mtime_t i_duration;   /* how long to display the image, 0 stands
00091                            for "until next subtitle" */
00092 
00093   uint16_t i_x_start, i_y_start; /* position of top leftmost pixel of
00094                                     image when displayed */
00095   uint16_t i_width, i_height;    /* dimensions in pixels of image */
00096 
00097   uint8_t p_palette[4][4];       /* Palette of colors used in subtitle */
00098   uint8_t p_palette_highlight[4][4];
00099 };
00100 
00101 /*****************************************************************************
00102  * DecoderOpen: open/initialize the cvdsub decoder.
00103  *****************************************************************************/
00104 static int DecoderOpen( vlc_object_t *p_this )
00105 {
00106     decoder_t     *p_dec = (decoder_t*)p_this;
00107     decoder_sys_t *p_sys;
00108 
00109     if( p_dec->fmt_in.i_codec != VLC_FOURCC( 'c','v','d',' ' ) )
00110     {
00111         return VLC_EGENERIC;
00112     }
00113 
00114     p_dec->p_sys = p_sys = malloc( sizeof( decoder_sys_t ) );
00115 
00116     p_sys->b_packetizer  = VLC_FALSE;
00117 
00118     p_sys->i_state = SUBTITLE_BLOCK_EMPTY;
00119     p_sys->p_spu   = NULL;
00120 
00121     es_format_Init( &p_dec->fmt_out, SPU_ES, VLC_FOURCC( 'c','v','d',' ' ) );
00122 
00123     p_dec->pf_decode_sub = Decode;
00124     p_dec->pf_packetize  = Packetize;
00125 
00126     return VLC_SUCCESS;
00127 }
00128 
00129 /*****************************************************************************
00130  * PacketizerOpen: open/initialize the cvdsub packetizer.
00131  *****************************************************************************/
00132 static int PacketizerOpen( vlc_object_t *p_this )
00133 {
00134     decoder_t *p_dec = (decoder_t*)p_this;
00135 
00136     if( DecoderOpen( p_this ) != VLC_SUCCESS ) return VLC_EGENERIC;
00137 
00138     p_dec->p_sys->b_packetizer = VLC_TRUE;
00139 
00140     return VLC_SUCCESS;
00141 }
00142 
00143 /*****************************************************************************
00144  * DecoderClose: closes the cvdsub decoder/packetizer.
00145  *****************************************************************************/
00146 void DecoderClose( vlc_object_t *p_this )
00147 {
00148     decoder_t     *p_dec = (decoder_t*)p_this;
00149     decoder_sys_t *p_sys = p_dec->p_sys;
00150 
00151     if( p_sys->p_spu ) block_ChainRelease( p_sys->p_spu );
00152     free( p_sys );
00153 }
00154 
00155 /*****************************************************************************
00156  * Decode:
00157  *****************************************************************************/
00158 static subpicture_t *Decode( decoder_t *p_dec, block_t **pp_block )
00159 {
00160     block_t *p_block, *p_spu;
00161 
00162     if( pp_block == NULL || *pp_block == NULL ) return NULL;
00163 
00164     p_block = *pp_block;
00165     *pp_block = NULL;
00166 
00167     if( !(p_spu = Reassemble( p_dec, p_block )) ) return NULL;
00168 
00169     /* Parse and decode */
00170     return DecodePacket( p_dec, p_spu );
00171 }
00172 
00173 /*****************************************************************************
00174  * Packetize:
00175  *****************************************************************************/
00176 static block_t *Packetize( decoder_t *p_dec, block_t **pp_block )
00177 {
00178     block_t *p_block, *p_spu;
00179 
00180     if( pp_block == NULL || *pp_block == NULL ) return NULL;
00181 
00182     p_block = *pp_block;
00183     *pp_block = NULL;
00184 
00185     if( !(p_spu = Reassemble( p_dec, p_block )) ) return NULL;
00186 
00187     p_spu->i_dts = p_spu->i_pts;
00188     p_spu->i_length = 0;
00189 
00190     return p_spu;
00191 }
00192 
00193 
00194 /*****************************************************************************
00195  Reassemble:
00196 
00197  Data for single screen subtitle may come in several non-contiguous
00198  packets of a stream. This routine is called when the next packet in
00199  the stream comes in. The job of this routine is to parse the header,
00200  if this is the beginning, and combine the packets into one complete
00201  subtitle unit.
00202 
00203  If everything is complete, we will return a block. Otherwise return
00204  NULL.
00205 
00206  *****************************************************************************/
00207 #define SPU_HEADER_LEN 1
00208 
00209 static block_t *Reassemble( decoder_t *p_dec, block_t *p_block )
00210 {
00211     decoder_sys_t *p_sys = p_dec->p_sys;
00212     uint8_t *p_buffer;
00213 
00214     if( p_block->i_buffer < SPU_HEADER_LEN )
00215     {
00216         msg_Dbg( p_dec, "invalid packet header (size %d < %d)" ,
00217                  p_block->i_buffer, SPU_HEADER_LEN );
00218         block_Release( p_block );
00219         return NULL;
00220     }
00221 
00222     p_buffer = p_block->p_buffer;
00223 
00224     /* From the scant data on the format, there is only only way known
00225      * to detect the first packet in a subtitle.  The first packet
00226      * seems to have a valid PTS while later packets for the same
00227      * image don't. */
00228     if( p_sys->i_state == SUBTITLE_BLOCK_EMPTY && p_block->i_pts == 0 )
00229     {
00230         msg_Warn( p_dec, "first packet expected but no PTS present");
00231         return NULL;
00232     }
00233 
00234     p_block->p_buffer += SPU_HEADER_LEN;
00235     p_block->i_buffer -= SPU_HEADER_LEN;
00236 
00237     /* First packet in the subtitle block */
00238     if( p_sys->i_state == SUBTITLE_BLOCK_EMPTY ) ParseHeader( p_dec, p_block );
00239 
00240     block_ChainAppend( &p_sys->p_spu, p_block );
00241     p_sys->p_spu = block_ChainGather( p_sys->p_spu );
00242 
00243     if( p_sys->p_spu->i_buffer >= p_sys->i_spu_size )
00244     {
00245         block_t *p_spu = p_sys->p_spu;
00246 
00247         if( p_spu->i_buffer != p_sys->i_spu_size )
00248         {
00249             msg_Warn( p_dec, "SPU packets size=%d should be %d",
00250                       p_spu->i_buffer, p_sys->i_spu_size );
00251         }
00252 
00253         msg_Dbg( p_dec, "subtitle packet complete, size=%d", p_spu->i_buffer);
00254 
00255         ParseMetaInfo( p_dec, p_spu );
00256 
00257         p_sys->i_state = SUBTITLE_BLOCK_EMPTY;
00258         p_sys->p_spu = 0;
00259         return p_spu;
00260     }
00261     else
00262     {
00263         /* Not last block in subtitle, so wait for another. */
00264         p_sys->i_state = SUBTITLE_BLOCK_PARTIAL;
00265     }
00266 
00267     return NULL;
00268 }
00269 
00270 /*
00271   We do not have information on the subtitle format used on CVD's
00272   except the submux sample code and a couple of samples of dubious
00273   origin. Thus, this is the result of reading some code whose
00274   correctness is not known and some experimentation.
00275   
00276   CVD subtitles are different in several ways from SVCD OGT subtitles.
00277   Image comes first and metadata is at the end.  So that the metadata
00278   can be found easily, the subtitle packet starts with two bytes
00279   (everything is big-endian again) that give the total size of the
00280   subtitle data and the offset to the metadata - i.e. size of the
00281   image data plus the four bytes at the beginning.
00282  
00283   Image data comes interlaced is run-length encoded.  Each field is a
00284   four-bit nibble. Each nibble contains a two-bit repeat count and a
00285   two-bit color number so that up to three pixels can be described in
00286   four bits.  The function of a 0 repeat count is unknown; it might be
00287   used for RLE extension.  However when the full nibble is zero, the
00288   rest of the line is filled with the color value in the next nibble.
00289   It is unknown what happens if the color value is greater than three.
00290   The rest seems to use a 4-entries palette.  It is not impossible
00291   that the fill-line complete case above is not as described and the
00292   zero repeat count means fill line.  The sample code never produces
00293   this, so it may be untested.
00294 */
00295 
00296 static void ParseHeader( decoder_t *p_dec, block_t *p_block )
00297 {
00298     decoder_sys_t *p_sys = p_dec->p_sys;
00299     uint8_t *p = p_block->p_buffer;
00300 
00301     p_sys->i_spu_size = (p[0] << 8) + p[1] + 4; p += 2;
00302 
00303     /* FIXME: check data sanity */
00304     p_sys->metadata_offset = (p[0] <<  8) +   p[1]; p +=2;
00305     p_sys->metadata_length = p_sys->i_spu_size - p_sys->metadata_offset;
00306 
00307     p_sys->i_image_offset = 4;
00308     p_sys->i_image_length = p_sys->metadata_offset - p_sys->i_image_offset;
00309   
00310 #ifdef DEBUG_CVDSUB
00311     msg_Dbg( p_dec, "total size: %d  image size: %d",
00312              p_sys->i_spu_size, p_sys->i_image_length );
00313 #endif
00314 
00315 }
00316 
00317 /* 
00318   We parse the metadata information here. 
00319 
00320   Although metadata information does not have to come in a fixed field
00321   order, every metadata field consists of a tag byte followed by
00322   parameters. In all cases known, the size including tag byte is
00323   exactly four bytes in length.
00324 */
00325 
00326 #define ExtractXY(x, y) x = ((p[1]&0x0f)<<6) + (p[2]>>2); \
00327                         y = ((p[2]&0x03)<<8) + p[3];
00328 
00329 static void ParseMetaInfo( decoder_t *p_dec, block_t *p_spu  )
00330 {
00331     /* Last packet in subtitle block. */
00332 
00333     decoder_sys_t *p_sys = p_dec->p_sys;
00334     uint8_t       *p     = p_spu->p_buffer + p_sys->metadata_offset;
00335     uint8_t       *p_end = p + p_sys->metadata_length;
00336   
00337     for( ; p < p_end; p += 4 )
00338     {
00339         switch( p[0] )
00340         {
00341         case 0x04: /* subtitle duration in 1/90000ths of a second */
00342             p_sys->i_duration = (p[1]<<16) + (p[2]<<8) + p[3];
00343 
00344 #ifdef DEBUG_CVDSUB
00345             msg_Dbg( p_dec, "subtitle display duration %lu secs",
00346                      (long unsigned int)(p_sys->i_duration / 90000) );
00347 #endif
00348             p_sys->i_duration *= 100 / 9;
00349             break;
00350       
00351         case 0x0c: /* unknown */
00352 #ifdef DEBUG_CVDSUB
00353             msg_Dbg( p_dec, "subtitle command unknown 0x%0x 0x%0x 0x%0x 0x%0x",
00354                      (int)p[0], (int)p[1], (int)p[2], (int)p[3] );
00355 #endif
00356             break;
00357       
00358         case 0x17: /* coordinates of subtitle upper left x, y position */
00359             ExtractXY(p_sys->i_x_start, p_sys->i_y_start);
00360 
00361 #ifdef DEBUG_CVDSUB
00362             msg_Dbg( p_dec, "start position (%d,%d)",
00363                      p_sys->i_x_start, p_sys->i_y_start );
00364 #endif
00365             break;
00366       
00367         case 0x1f: /* coordinates of subtitle bottom right x, y position */
00368         {
00369             int lastx;
00370             int lasty;
00371             ExtractXY(lastx, lasty);
00372             p_sys->i_width  = lastx - p_sys->i_x_start + 1;
00373             p_sys->i_height = lasty - p_sys->i_y_start + 1;
00374 
00375 #ifdef DEBUG_CVDSUB
00376             msg_Dbg( p_dec, "end position (%d,%d), w x h: %dx%d",
00377                      lastx, lasty, p_sys->i_width, p_sys->i_height );
00378 #endif
00379             break;
00380         }
00381       
00382         case 0x24:
00383         case 0x25:
00384         case 0x26:
00385         case 0x27: 
00386         {
00387             uint8_t v = p[0] - 0x24;
00388 
00389 #ifdef DEBUG_CVDSUB
00390             /* Primary Palette */
00391             msg_Dbg( p_dec, "primary palette %d (y,u,v): (0x%0x,0x%0x,0x%0x)",
00392                      (int)v, (int)p[1], (int)p[2], (int)p[3] );
00393 #endif
00394 
00395             p_sys->p_palette[v][0] = p[1]; /* Y */
00396             p_sys->p_palette[v][1] = p[3]; /* Cr / V */
00397             p_sys->p_palette[v][2] = p[2]; /* Cb / U */
00398             break;
00399         }
00400 
00401         case 0x2c:
00402         case 0x2d:
00403         case 0x2e:
00404         case 0x2f:
00405         {
00406             uint8_t v = p[0] - 0x2c;
00407 
00408 #ifdef DEBUG_CVDSUB
00409             msg_Dbg( p_dec,"highlight palette %d (y,u,v): (0x%0x,0x%0x,0x%0x)",
00410                      (int)v, (int)p[1], (int)p[2], (int)p[3] );
00411 #endif
00412 
00413             /* Highlight Palette */
00414             p_sys->p_palette_highlight[v][0] = p[1]; /* Y */
00415             p_sys->p_palette_highlight[v][1] = p[3]; /* Cr / V */
00416             p_sys->p_palette_highlight[v][2] = p[2]; /* Cb / U */
00417             break;
00418         }
00419 
00420         case 0x37:
00421             /* transparency for primary palette */
00422             p_sys->p_palette[0][3] = (p[3] & 0x0f) << 4;
00423             p_sys->p_palette[1][3] = (p[3] >> 4) << 4;
00424             p_sys->p_palette[2][3] = (p[2] & 0x0f) << 4;
00425             p_sys->p_palette[3][3] = (p[2] >> 4) << 4;
00426 
00427 #ifdef DEBUG_CVDSUB
00428             msg_Dbg( p_dec, "transparency for primary palette 0..3: "
00429                      "0x%0x 0x%0x 0x%0x 0x%0x",
00430                      (int)p_sys->p_palette[0][3], (int)p_sys->p_palette[1][3],
00431                      (int)p_sys->p_palette[2][3], (int)p_sys->p_palette[3][3]);
00432 #endif
00433             break;
00434       
00435         case 0x3f:
00436             /* transparency for highlight palette */
00437             p_sys->p_palette_highlight[0][3] = (p[2] & 0x0f) << 4;
00438             p_sys->p_palette_highlight[1][3] = (p[2] >> 4) << 4;
00439             p_sys->p_palette_highlight[2][3] = (p[1] & 0x0f) << 4;
00440             p_sys->p_palette_highlight[3][3] = (p[1] >> 4) << 4;
00441 
00442 #ifdef DEBUG_CVDSUB
00443             msg_Dbg( p_dec, "transparency for highlight palette 0..3: "
00444                      "0x%0x 0x%0x 0x%0x 0x%0x",
00445                      (int)p_sys->p_palette_highlight[0][3],
00446                      (int)p_sys->p_palette_highlight[1][3],
00447                      (int)p_sys->p_palette_highlight[2][3],
00448                      (int)p_sys->p_palette_highlight[3][3] );
00449 #endif
00450             break;
00451 
00452         case 0x47:
00453             /* offset to start of even rows of interlaced image, we correct
00454              * to make it relative to i_image_offset (usually 4) */
00455             p_sys->first_field_offset =
00456                 (p[2] << 8) + p[3] - p_sys->i_image_offset;
00457 #ifdef DEBUG_CVDSUB
00458             msg_Dbg( p_dec, "1st_field_offset %d", p_sys->first_field_offset );
00459 #endif
00460             break;
00461 
00462         case 0x4f:
00463             /* offset to start of odd rows of interlaced image, we correct
00464              * to make it relative to i_image_offset (usually 4) */
00465             p_sys->second_field_offset =
00466                 (p[2] << 8) + p[3] - p_sys->i_image_offset;
00467 #ifdef DEBUG_CVDSUB
00468             msg_Dbg( p_dec, "2nd_field_offset %d", p_sys->second_field_offset);
00469 #endif
00470             break;
00471 
00472         default:
00473 #ifdef DEBUG_CVDSUB
00474             msg_Warn( p_dec, "unknown sequence in control header " 
00475                       "0x%0x 0x%0x 0x%0x 0x%0x", p[0], p[1], p[2], p[3]);
00476 #endif
00477         }
00478     }
00479 }
00480 
00481 /*****************************************************************************
00482  * DecodePacket: parse and decode an SPU packet
00483  *****************************************************************************
00484  * This function parses and decodes an SPU packet and, if valid, returns a
00485  * subpicture.
00486  *****************************************************************************/
00487 static subpicture_t *DecodePacket( decoder_t *p_dec, block_t *p_data )
00488 {
00489     decoder_sys_t *p_sys = p_dec->p_sys;
00490     subpicture_t  *p_spu;
00491     subpicture_region_t *p_region;
00492     video_format_t fmt;
00493     int i;
00494 
00495     /* Allocate the subpicture internal data. */
00496     p_spu = p_dec->pf_spu_buffer_new( p_dec );
00497     if( !p_spu ) return NULL;
00498 
00499     p_spu->i_x = p_sys->i_x_start;
00500     p_spu->i_x = p_spu->i_x * 3 / 4; /* FIXME: use aspect ratio for x? */
00501     p_spu->i_y = p_sys->i_y_start;
00502     p_spu->i_start = p_data->i_pts;
00503     p_spu->i_stop  = p_data->i_pts + p_sys->i_duration;
00504     p_spu->b_ephemer = VLC_TRUE;
00505 
00506     /* Create new SPU region */
00507     memset( &fmt, 0, sizeof(video_format_t) );
00508     fmt.i_chroma = VLC_FOURCC('Y','U','V','P');
00509     fmt.i_aspect = VOUT_ASPECT_FACTOR;
00510     fmt.i_width = fmt.i_visible_width = p_sys->i_width;
00511     fmt.i_height = fmt.i_visible_height = p_sys->i_height;
00512     fmt.i_x_offset = fmt.i_y_offset = 0;
00513     p_region = p_spu->pf_create_region( VLC_OBJECT(p_dec), &fmt );
00514     if( !p_region )
00515     {
00516         msg_Err( p_dec, "cannot allocate SPU region" );
00517         //goto error;
00518     }
00519 
00520     p_spu->p_region = p_region;
00521     p_region->i_x = p_region->i_y = 0;
00522 
00523     /* Build palette */
00524     fmt.p_palette->i_entries = 4;
00525     for( i = 0; i < fmt.p_palette->i_entries; i++ )
00526     {
00527         fmt.p_palette->palette[i][0] = p_sys->p_palette[i][0];
00528         fmt.p_palette->palette[i][1] = p_sys->p_palette[i][1];
00529         fmt.p_palette->palette[i][2] = p_sys->p_palette[i][2];
00530         fmt.p_palette->palette[i][3] = p_sys->p_palette[i][3];
00531     }
00532 
00533     RenderImage( p_dec, p_data, p_region );
00534 
00535     return p_spu;
00536 }
00537 
00538 /*****************************************************************************
00539  * ParseImage: parse and render the image part of the subtitle
00540  *****************************************************************************
00541  This part parses the subtitle graphical data and renders it. 
00542 
00543  Image data comes interlaced and is run-length encoded (RLE). Each
00544  field is a four-bit nibbles that is further subdivided in a two-bit
00545  repeat count and a two-bit color number - up to three pixels can be
00546  described in four bits.  What a 0 repeat count means is unknown.  It
00547  might be used for RLE extension.  There is a special case of a 0
00548  repeat count though.  When the full nibble is zero, the rest of the
00549  line is filled with the color value in the next nibble.  It is
00550  unknown what happens if the color value is greater than three.  The
00551  rest seems to use a 4-entries palette.  It is not impossible that the
00552  fill-line complete case above is not as described and the zero repeat
00553  count means fill line.  The sample code never produces this, so it
00554  may be untested.
00555 
00556  However we'll transform this so that that the RLE is expanded and
00557  interlacing will also be removed. On output each pixel entry will by 
00558  a 4-bit alpha (filling 8 bits), and 8-bit y, u, and v entry.
00559 
00560  *****************************************************************************/
00561 static void RenderImage( decoder_t *p_dec, block_t *p_data,
00562                          subpicture_region_t *p_region )
00563 {
00564     decoder_sys_t *p_sys = p_dec->p_sys;
00565     uint8_t *p_dest = p_region->picture.Y_PIXELS;
00566     int i_field;            /* The subtitles are interlaced */
00567     int i_row, i_column;    /* scanline row/column number */
00568     uint8_t i_color, i_count;
00569     bs_t bs;
00570 
00571     bs_init( &bs, p_data->p_buffer + p_sys->i_image_offset,
00572              p_data->i_buffer - p_sys->i_image_offset );
00573 
00574     for( i_field = 0; i_field < 2; i_field++ )
00575     {
00576         for( i_row = i_field; i_row < p_sys->i_height; i_row += 2 )
00577         {
00578             for( i_column = 0; i_column < p_sys->i_width; i_column++ )
00579             {
00580                 uint8_t i_val = bs_read( &bs, 4 );
00581 
00582                 if( i_val == 0 )
00583                 {
00584                     /* Fill the rest of the line with next color */
00585                     i_color = bs_read( &bs, 4 );
00586 
00587                     memset( &p_dest[i_row * p_region->picture.Y_PITCH +
00588                                     i_column], i_color,
00589                             p_sys->i_width - i_column );
00590                     i_column = p_sys->i_width;
00591                     continue;
00592                 }
00593                 else
00594                 {
00595                     /* Normal case: get color and repeat count */
00596                     i_count = (i_val >> 2);
00597                     i_color = i_val & 0x3;
00598 
00599                     i_count = __MIN( i_count, p_sys->i_width - i_column );
00600 
00601                     memset( &p_dest[i_row * p_region->picture.Y_PITCH +
00602                                     i_column], i_color, i_count );
00603                     i_column += i_count - 1;
00604                     continue;
00605                 }
00606             }
00607 
00608             bs_align( &bs );
00609         }
00610     }
00611 }

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