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

dvbsub.c

00001 /*****************************************************************************
00002  * dvbsub.c : DVB subtitles decoder
00003  *            DVB subtitles encoder (developed for Anevia, www.anevia.com)
00004  *****************************************************************************
00005  * Copyright (C) 2003 ANEVIA
00006  * Copyright (C) 2003-2005 VideoLAN (Centrale Réseaux) and its contributors
00007  * $Id: dvbsub.c 12708 2005-09-29 14:31:26Z jpsaman $
00008  *
00009  * Authors: Gildas Bazin <[email protected]>
00010  *          Damien LUCAS <[email protected]>
00011  *          Laurent Aimar <[email protected]>
00012  *          Jean-Paul Saman <jpsaman #_at_# m2x dot nl>
00013  *
00014  * This program is free software; you can redistribute it and/or modify
00015  * it under the terms of the GNU General Public License as published by
00016  * the Free Software Foundation; either version 2 of the License, or
00017  * (at your option) any later version.
00018  *
00019  * This program is distributed in the hope that it will be useful,
00020  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00021  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00022  * GNU General Public License for more details.
00023  *
00024  * You should have received a copy of the GNU General Public License
00025  * along with this program; if not, write to the Free Software
00026  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
00027  *****************************************************************************/
00028 /*****************************************************************************
00029  * Preamble
00030  *
00031  * FIXME:
00032  * DVB subtitles coded as strings of characters are not handled correctly.
00033  * The character codes in the string should actually be indexes refering to a
00034  * character table identified in the subtitle descriptor.
00035  *****************************************************************************/
00036 #include <vlc/vlc.h>
00037 #include <vlc/vout.h>
00038 #include <vlc/decoder.h>
00039 #include <vlc/sout.h>
00040 
00041 #include "vlc_bits.h"
00042 
00043 /* #define DEBUG_DVBSUB 1 */
00044 
00045 #define POSX_TEXT N_("X coordinate of the subpicture")
00046 #define POSX_LONGTEXT N_("You can reposition the subpicture by providing another value here." )
00047 
00048 #define POSY_TEXT N_("Y coordinate of the subpicture")
00049 #define POSY_LONGTEXT N_("You can reposition the subpicture by providing another value here." )
00050 
00051 #define POS_TEXT N_("Subpicture position")
00052 #define POS_LONGTEXT N_( \
00053   "You can enforce the subpicture position on the video " \
00054   "(0=center, 1=left, 2=right, 4=top, 8=bottom, you can " \
00055   "also use combinations of these values).")
00056 
00057 #define ENC_POSX_TEXT N_("X coordinate of the encoded subpicture")
00058 #define ENC_POSX_LONGTEXT N_("You can reposition the subpicture by providing another value here." )
00059 
00060 #define ENC_POSY_TEXT N_("Y coordinate of encoded the subpicture")
00061 #define ENC_POSY_LONGTEXT N_("You can reposition the subpicture by providing another value here." )
00062 
00063 #define TIMEOUT_TEXT N_("Timeout of subpictures")
00064 #define TIMEOUT_LONGTEXT N_( \
00065     "Subpictures get a default timeout of 15 seconds added to their remaining time." \
00066     "This will ensure that they are at least the specified time visible.")
00067 
00068 static int pi_pos_values[] = { 0, 1, 2, 4, 8, 5, 6, 9, 10 };
00069 static char *ppsz_pos_descriptions[] =
00070 { N_("Center"), N_("Left"), N_("Right"), N_("Top"), N_("Bottom"),
00071   N_("Top-Left"), N_("Top-Right"), N_("Bottom-Left"), N_("Bottom-Right") };
00072 
00073 /*****************************************************************************
00074  * Module descriptor.
00075  *****************************************************************************/
00076 static int  Open ( vlc_object_t * );
00077 static void Close( vlc_object_t * );
00078 static subpicture_t *Decode( decoder_t *, block_t ** );
00079 
00080 static int OpenEncoder  ( vlc_object_t * );
00081 static void CloseEncoder( vlc_object_t * );
00082 static block_t *Encode  ( encoder_t *, subpicture_t * );
00083 
00084 vlc_module_begin();
00085 #   define DVBSUB_CFG_PREFIX "dvbsub-"
00086     set_description( _("DVB subtitles decoder") );
00087     set_capability( "decoder", 50 );
00088     set_category( CAT_INPUT );
00089     set_subcategory( SUBCAT_INPUT_SCODEC );
00090     set_callbacks( Open, Close );
00091 
00092     add_integer( DVBSUB_CFG_PREFIX "position", 8, NULL, POS_TEXT, POS_LONGTEXT, VLC_TRUE );
00093         change_integer_list( pi_pos_values, ppsz_pos_descriptions, 0 );
00094     add_integer( DVBSUB_CFG_PREFIX "x", -1, NULL, POSX_TEXT, POSX_LONGTEXT, VLC_FALSE );
00095     add_integer( DVBSUB_CFG_PREFIX "y", -1, NULL, POSY_TEXT, POSY_LONGTEXT, VLC_FALSE );
00096 
00097 #   define ENC_CFG_PREFIX "sout-dvbsub-"
00098     add_submodule();
00099     set_description( _("DVB subtitles encoder") );
00100     set_capability( "encoder", 100 );
00101     set_callbacks( OpenEncoder, CloseEncoder );
00102 
00103     add_integer( ENC_CFG_PREFIX "x", -1, NULL, ENC_POSX_TEXT, ENC_POSX_LONGTEXT, VLC_FALSE );
00104     add_integer( ENC_CFG_PREFIX "y", -1, NULL, ENC_POSY_TEXT, ENC_POSY_LONGTEXT, VLC_FALSE );
00105     add_integer( ENC_CFG_PREFIX "timeout", 15, NULL, TIMEOUT_TEXT, TIMEOUT_LONGTEXT, VLC_FALSE );    
00106 vlc_module_end();
00107 
00108 static const char *ppsz_enc_options[] = { NULL };
00109 
00110 /****************************************************************************
00111  * Local structures
00112  ****************************************************************************
00113  * Those structures refer closely to the ETSI 300 743 Object model
00114  ****************************************************************************/
00115 
00116 /* The object definition gives the position of the object in a region */
00117 typedef struct dvbsub_objectdef_s
00118 {
00119     int i_id;
00120     int i_type;
00121     int i_x;
00122     int i_y;
00123     int i_fg_pc;
00124     int i_bg_pc;
00125     char *psz_text; /* for string of characters objects */
00126 
00127 } dvbsub_objectdef_t;
00128 
00129 /* The entry in the palette CLUT */
00130 typedef struct
00131 {
00132     uint8_t                 Y;
00133     uint8_t                 Cr;
00134     uint8_t                 Cb;
00135     uint8_t                 T;
00136 
00137 } dvbsub_color_t;
00138 
00139 /* */
00140 typedef struct dvbsub_clut_s
00141 {
00142     uint8_t                 i_id;
00143     uint8_t                 i_version;
00144     dvbsub_color_t          c_2b[4];
00145     dvbsub_color_t          c_4b[16];
00146     dvbsub_color_t          c_8b[256];
00147 
00148     struct dvbsub_clut_s    *p_next;
00149 
00150 } dvbsub_clut_t;
00151 
00152 /* The Region is an aera on the image
00153  * with a list of the object definitions associated and a CLUT */
00154 typedef struct dvbsub_region_s
00155 {
00156     int i_id;
00157     int i_version;
00158     int i_x;
00159     int i_y;
00160     int i_width;
00161     int i_height;
00162     int i_level_comp;
00163     int i_depth;
00164     int i_clut;
00165 
00166     uint8_t *p_pixbuf;
00167 
00168     int                    i_object_defs;
00169     dvbsub_objectdef_t     *p_object_defs;
00170 
00171     struct dvbsub_region_s *p_next;
00172 
00173 } dvbsub_region_t;
00174 
00175 /* The object definition gives the position of the object in a region */
00176 typedef struct dvbsub_regiondef_s
00177 {
00178     int i_id;
00179     int i_x;
00180     int i_y;
00181 
00182 } dvbsub_regiondef_t;
00183 
00184 /* The page defines the list of regions */
00185 typedef struct
00186 {
00187     int i_id;
00188     int i_timeout; /* in seconds */
00189     int i_state;
00190     int i_version;
00191 
00192     int                i_region_defs;
00193     dvbsub_regiondef_t *p_region_defs;
00194 
00195 } dvbsub_page_t;
00196 
00197 struct decoder_sys_t
00198 {
00199     bs_t            bs;
00200 
00201     /* Decoder internal data */
00202     int             i_id;
00203     int             i_ancillary_id;
00204     mtime_t         i_pts;
00205 
00206     vlc_bool_t      b_absolute;
00207     int             i_spu_position;
00208     int             i_spu_x;
00209     int             i_spu_y;
00210 
00211     vlc_bool_t      b_page;
00212     dvbsub_page_t   *p_page;
00213     dvbsub_region_t *p_regions;
00214     dvbsub_clut_t   *p_cluts;
00215     dvbsub_clut_t   default_clut;
00216 };
00217 
00218 
00219 /* List of different SEGMENT TYPES */
00220 /* According to EN 300-743, table 2 */
00221 #define DVBSUB_ST_PAGE_COMPOSITION      0x10
00222 #define DVBSUB_ST_REGION_COMPOSITION    0x11
00223 #define DVBSUB_ST_CLUT_DEFINITION       0x12
00224 #define DVBSUB_ST_OBJECT_DATA           0x13
00225 #define DVBSUB_ST_ENDOFDISPLAY          0x80
00226 #define DVBSUB_ST_STUFFING              0xff
00227 /* List of different OBJECT TYPES */
00228 /* According to EN 300-743, table 6 */
00229 #define DVBSUB_OT_BASIC_BITMAP          0x00
00230 #define DVBSUB_OT_BASIC_CHAR            0x01
00231 #define DVBSUB_OT_COMPOSITE_STRING      0x02
00232 /* Pixel DATA TYPES */
00233 /* According to EN 300-743, table 9 */ 
00234 #define DVBSUB_DT_2BP_CODE_STRING       0x10
00235 #define DVBSUB_DT_4BP_CODE_STRING       0x11
00236 #define DVBSUB_DT_8BP_CODE_STRING       0x12
00237 #define DVBSUB_DT_24_TABLE_DATA         0x20
00238 #define DVBSUB_DT_28_TABLE_DATA         0x21
00239 #define DVBSUB_DT_48_TABLE_DATA         0x22
00240 #define DVBSUB_DT_END_LINE              0xf0
00241 /* List of different Page Composition Segment state */
00242 /* According to EN 300-743, 7.2.1 table 3 */
00243 #define DVBSUB_PCS_STATE_ACQUISITION    0x01
00244 #define DVBSUB_PCS_STATE_CHANGE         0x10
00245 
00246 /*****************************************************************************
00247  * Local prototypes
00248  *****************************************************************************/
00249 static void decode_segment( decoder_t *, bs_t * );
00250 static void decode_page_composition( decoder_t *, bs_t * );
00251 static void decode_region_composition( decoder_t *, bs_t * );
00252 static void decode_object( decoder_t *, bs_t * );
00253 static void decode_clut( decoder_t *, bs_t * );
00254 static void free_all( decoder_t * );
00255 
00256 static void default_clut_init( decoder_t * );
00257 
00258 static subpicture_t *render( decoder_t * );
00259 
00260 /*****************************************************************************
00261  * Open: probe the decoder and return score
00262  *****************************************************************************
00263  * Tries to launch a decoder and return score so that the interface is able
00264  * to chose.
00265  *****************************************************************************/
00266 static int Open( vlc_object_t *p_this )
00267 {
00268     decoder_t     *p_dec = (decoder_t *) p_this;
00269     decoder_sys_t *p_sys;
00270     vlc_value_t    val;
00271     int i_posx, i_posy;
00272 
00273     if( p_dec->fmt_in.i_codec != VLC_FOURCC('d','v','b','s') )
00274     {
00275         return VLC_EGENERIC;
00276     }
00277 
00278     p_dec->pf_decode_sub = Decode;
00279     p_sys = p_dec->p_sys = malloc( sizeof(decoder_sys_t) );
00280     memset( p_sys, 0, sizeof(decoder_sys_t) );
00281 
00282     p_sys->i_pts          = (mtime_t) 0;    
00283     p_sys->i_id           = p_dec->fmt_in.subs.dvb.i_id & 0xFFFF;
00284     p_sys->i_ancillary_id = p_dec->fmt_in.subs.dvb.i_id >> 16;
00285 
00286     p_sys->p_regions      = NULL;
00287     p_sys->p_cluts        = NULL;
00288     p_sys->p_page         = NULL;
00289 
00290     var_Create( p_this, DVBSUB_CFG_PREFIX "position",
00291                 VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
00292     var_Get( p_this, DVBSUB_CFG_PREFIX "position", &val );
00293     p_sys->i_spu_position = val.i_int;
00294     var_Create( p_this, DVBSUB_CFG_PREFIX "x",
00295                 VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
00296     var_Get( p_this, DVBSUB_CFG_PREFIX "x", &val );
00297     i_posx = val.i_int;
00298     var_Create( p_this, DVBSUB_CFG_PREFIX "y",
00299                 VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
00300     var_Get( p_this, DVBSUB_CFG_PREFIX "y", &val );
00301     i_posy = val.i_int;
00302 
00303     /* Check if subpicture position was overridden */
00304     p_sys->b_absolute = VLC_TRUE;
00305     p_sys->i_spu_x = p_sys->i_spu_y = 0;
00306 
00307     if( i_posx >= 0 && i_posy >= 0 )
00308     {
00309         p_sys->b_absolute = VLC_FALSE;
00310         p_sys->i_spu_x = i_posx;
00311         p_sys->i_spu_y = i_posy;
00312     }
00313 
00314     es_format_Init( &p_dec->fmt_out, SPU_ES, VLC_FOURCC( 'd','v','b','s' ) );
00315 
00316     default_clut_init( p_dec );
00317 
00318     return VLC_SUCCESS;
00319 }
00320 
00321 /*****************************************************************************
00322  * Close:
00323  *****************************************************************************/
00324 static void Close( vlc_object_t *p_this )
00325 {
00326     decoder_t     *p_dec = (decoder_t*) p_this;
00327     decoder_sys_t *p_sys = p_dec->p_sys;
00328 
00329     var_Destroy( p_this, DVBSUB_CFG_PREFIX "x" );
00330     var_Destroy( p_this, DVBSUB_CFG_PREFIX "y" );
00331     var_Destroy( p_this, DVBSUB_CFG_PREFIX "position" );    
00332 
00333     free_all( p_dec );
00334     free( p_sys );
00335 }
00336 
00337 /*****************************************************************************
00338  * Decode:
00339  *****************************************************************************/
00340 static subpicture_t *Decode( decoder_t *p_dec, block_t **pp_block )
00341 {
00342     decoder_sys_t *p_sys = p_dec->p_sys;
00343     block_t       *p_block;
00344     subpicture_t  *p_spu = NULL;
00345 
00346     if( pp_block == NULL || *pp_block == NULL ) return NULL;
00347     p_block = *pp_block;
00348     *pp_block = NULL;
00349 
00350     p_sys->i_pts = p_block->i_pts;
00351     if( p_sys->i_pts <= 0 )
00352     {
00353 #ifdef DEBUG_DVBSUB
00354         /* Some DVB channels send stuffing segments in non-dated packets so
00355          * don't complain too loudly. */
00356         msg_Warn( p_dec, "non dated subtitle" );
00357 #endif
00358         block_Release( p_block );
00359         return NULL;
00360     }
00361 
00362     bs_init( &p_sys->bs, p_block->p_buffer, p_block->i_buffer );
00363 
00364     if( bs_read( &p_sys->bs, 8 ) != 0x20 ) /* Data identifier */
00365     {
00366         msg_Dbg( p_dec, "invalid data identifier" );
00367         block_Release( p_block );
00368         return NULL;
00369     }
00370 
00371     if( bs_read( &p_sys->bs, 8 ) ) /* Subtitle stream id */
00372     {
00373         msg_Dbg( p_dec, "invalid subtitle stream id" );
00374         block_Release( p_block );
00375         return NULL;
00376     }
00377 
00378 #ifdef DEBUG_DVBSUB
00379     msg_Dbg( p_dec, "subtitle packet received: "I64Fd, p_sys->i_pts );
00380 #endif
00381 
00382     p_sys->b_page = VLC_FALSE;
00383     while( bs_show( &p_sys->bs, 8 ) == 0x0f ) /* Sync byte */
00384     {
00385         decode_segment( p_dec, &p_sys->bs );
00386     }
00387 
00388     if( bs_read( &p_sys->bs, 8 ) != 0xff ) /* End marker */
00389     {
00390         msg_Warn( p_dec, "end marker not found (corrupted subtitle ?)" );
00391         block_Release( p_block );
00392         return NULL;
00393     }
00394 
00395     /* Check if the page is to be displayed */
00396     if( p_sys->p_page && p_sys->b_page ) p_spu = render( p_dec );
00397 
00398     block_Release( p_block );
00399 
00400     return p_spu;
00401 }
00402 
00403 /* following functions are local */
00404 
00405 /*****************************************************************************
00406  * default_clut_init: default clut as defined in EN 300-743 section 10
00407  *****************************************************************************/
00408 static void default_clut_init( decoder_t *p_dec )
00409 {
00410     decoder_sys_t *p_sys = p_dec->p_sys;
00411     uint8_t i;
00412 
00413 #define RGB_TO_Y(r, g, b) ((int16_t) 77 * r + 150 * g + 29 * b) / 256;
00414 #define RGB_TO_U(r, g, b) ((int16_t) -44 * r - 87 * g + 131 * b) / 256;
00415 #define RGB_TO_V(r, g, b) ((int16_t) 131 * r - 110 * g - 21 * b) / 256;
00416 
00417     /* 4 entries CLUT */
00418     for( i = 0; i < 4; i++ )
00419     {
00420         uint8_t R = 0, G = 0, B = 0, T = 0;
00421 
00422         if( !(i & 0x2) && !(i & 0x1) ) T = 0xFF;
00423         else if( !(i & 0x2) && (i & 0x1) ) R = G = B = 0xFF;
00424         else if( (i & 0x2) && !(i & 0x1) ) R = G = B = 0;
00425         else R = G = B = 0x7F;
00426 
00427         p_sys->default_clut.c_2b[i].Y = RGB_TO_Y(R,G,B);
00428         p_sys->default_clut.c_2b[i].Cr = RGB_TO_U(R,G,B);
00429         p_sys->default_clut.c_2b[i].Cb = RGB_TO_V(R,G,B);
00430         p_sys->default_clut.c_2b[i].T = T;
00431     }
00432 
00433     /* 16 entries CLUT */
00434     for( i = 0; i < 16; i++ )
00435     {
00436         uint8_t R = 0, G = 0, B = 0, T = 0;
00437 
00438         if( !(i & 0x8) )
00439         {
00440             if( !(i & 0x4) && !(i & 0x2) && !(i & 0x1) )
00441             {
00442                 T = 0xFF;
00443             }
00444             else
00445             {
00446                 R = (i & 0x1) ? 0xFF : 0;
00447                 G = (i & 0x2) ? 0xFF : 0;
00448                 B = (i & 0x4) ? 0xFF : 0;
00449             }
00450         }
00451         else
00452         {
00453             R = (i & 0x1) ? 0x7F : 0;
00454             G = (i & 0x2) ? 0x7F : 0;
00455             B = (i & 0x4) ? 0x7F : 0;
00456         }
00457 
00458         p_sys->default_clut.c_4b[i].Y = RGB_TO_Y(R,G,B);
00459         p_sys->default_clut.c_4b[i].Cr = RGB_TO_U(R,G,B);
00460         p_sys->default_clut.c_4b[i].Cb = RGB_TO_V(R,G,B);
00461         p_sys->default_clut.c_4b[i].T = T;
00462     }
00463 
00464     /* 256 entries CLUT */
00465     memset( p_sys->default_clut.c_8b, 0xFF, 256 * sizeof(dvbsub_color_t) );
00466 }
00467 
00468 static void decode_segment( decoder_t *p_dec, bs_t *s )
00469 {
00470     decoder_sys_t *p_sys = p_dec->p_sys;
00471     int i_type;
00472     int i_page_id;
00473     int i_size;
00474 
00475     /* sync_byte (already checked) */
00476     bs_skip( s, 8 );
00477 
00478     /* segment type */
00479     i_type = bs_read( s, 8 );
00480 
00481     /* page id */
00482     i_page_id = bs_read( s, 16 );
00483 
00484     /* segment size */
00485     i_size = bs_show( s, 16 );
00486 
00487     if( i_page_id != p_sys->i_id && i_page_id != p_sys->i_ancillary_id )
00488     {
00489 #ifdef DEBUG_DVBSUB
00490         msg_Dbg( p_dec, "subtitle skipped (page id: %i, %i)",
00491                  i_page_id, p_sys->i_id );
00492 #endif
00493         bs_skip( s,  8 * ( 2 + i_size ) );
00494         return;
00495     }
00496 
00497     if( p_sys->i_ancillary_id != p_sys->i_id &&
00498         i_type == DVBSUB_ST_PAGE_COMPOSITION &&
00499         i_page_id == p_sys->i_ancillary_id )
00500     {
00501 #ifdef DEBUG_DVBSUB
00502         msg_Dbg( p_dec, "skipped invalid ancillary subtitle packet" );
00503 #endif
00504         bs_skip( s,  8 * ( 2 + i_size ) );
00505         return;
00506     }
00507 
00508 #ifdef DEBUG_DVBSUB
00509     if( i_page_id == p_sys->i_id )
00510         msg_Dbg( p_dec, "segment (id: %i)", i_page_id );
00511     else
00512         msg_Dbg( p_dec, "ancillary segment (id: %i)", i_page_id );
00513 #endif
00514 
00515     switch( i_type )
00516     {
00517     case DVBSUB_ST_PAGE_COMPOSITION:
00518 #ifdef DEBUG_DVBSUB
00519         msg_Dbg( p_dec, "decode_page_composition" );
00520 #endif
00521         decode_page_composition( p_dec, s );
00522         break;
00523 
00524     case DVBSUB_ST_REGION_COMPOSITION:
00525 #ifdef DEBUG_DVBSUB
00526         msg_Dbg( p_dec, "decode_region_composition" );
00527 #endif
00528         decode_region_composition( p_dec, s );
00529         break;
00530 
00531     case DVBSUB_ST_CLUT_DEFINITION:
00532 #ifdef DEBUG_DVBSUB
00533         msg_Dbg( p_dec, "decode_clut" );
00534 #endif
00535         decode_clut( p_dec, s );
00536         break;
00537 
00538     case DVBSUB_ST_OBJECT_DATA:
00539 #ifdef DEBUG_DVBSUB
00540         msg_Dbg( p_dec, "decode_object" );
00541 #endif
00542         decode_object( p_dec, s );
00543         break;
00544 
00545     case DVBSUB_ST_ENDOFDISPLAY:
00546 #ifdef DEBUG_DVBSUB
00547         msg_Dbg( p_dec, "end of display" );
00548 #endif
00549         bs_skip( s,  8 * ( 2 + i_size ) );
00550         break;
00551 
00552     case DVBSUB_ST_STUFFING:
00553 #ifdef DEBUG_DVBSUB
00554         msg_Dbg( p_dec, "skip stuffing" );
00555 #endif
00556         bs_skip( s,  8 * ( 2 + i_size ) );
00557         break;
00558 
00559     default:
00560         msg_Warn( p_dec, "unsupported segment type: (%04x)", i_type );
00561         bs_skip( s,  8 * ( 2 + i_size ) );
00562         break;
00563     }
00564 }
00565 
00566 static void decode_clut( decoder_t *p_dec, bs_t *s )
00567 {
00568     decoder_sys_t *p_sys = p_dec->p_sys;
00569     uint16_t      i_segment_length;
00570     uint16_t      i_processed_length;
00571     dvbsub_clut_t *p_clut, *p_next;
00572     int           i_id, i_version;
00573 
00574     i_segment_length = bs_read( s, 16 );
00575     i_id             = bs_read( s, 8 );
00576     i_version        = bs_read( s, 4 );
00577 
00578     /* Check if we already have this clut */
00579     for( p_clut = p_sys->p_cluts; p_clut != NULL; p_clut = p_clut->p_next )
00580     {
00581         if( p_clut->i_id == i_id ) break;
00582     }
00583 
00584     /* Check version number */
00585     if( p_clut && p_clut->i_version == i_version )
00586     {
00587         /* Nothing to do */
00588         bs_skip( s, 8 * i_segment_length - 12 );
00589         return;
00590     }
00591 
00592     if( !p_clut )
00593     {
00594 #ifdef DEBUG_DVBSUB
00595         msg_Dbg( p_dec, "new clut: %i", i_id );
00596 #endif
00597         p_clut = malloc( sizeof(dvbsub_clut_t) );
00598         p_clut->p_next = p_sys->p_cluts;
00599         p_sys->p_cluts = p_clut;
00600     }
00601 
00602     /* Initialize to default clut */
00603     p_next = p_clut->p_next;
00604     *p_clut = p_sys->default_clut;
00605     p_clut->p_next = p_next;
00606 
00607     /* We don't have this version of the CLUT: Parse it */
00608     p_clut->i_version = i_version;
00609     p_clut->i_id = i_id;
00610     bs_skip( s, 4 ); /* Reserved bits */
00611     i_processed_length = 2;
00612     while( i_processed_length < i_segment_length )
00613     {
00614         uint8_t y, cb, cr, t;
00615         uint8_t i_id;
00616         uint8_t i_type;
00617 
00618         i_id = bs_read( s, 8 );
00619         i_type = bs_read( s, 3 );
00620 
00621         bs_skip( s, 4 );
00622 
00623         if( bs_read( s, 1 ) )
00624         {
00625             y  = bs_read( s, 8 );
00626             cr = bs_read( s, 8 );
00627             cb = bs_read( s, 8 );
00628             t  = bs_read( s, 8 );
00629             i_processed_length += 6;
00630         }
00631         else
00632         {
00633             y  = bs_read( s, 6 ) << 2;
00634             cr = bs_read( s, 4 ) << 4;
00635             cb = bs_read( s, 4 ) << 4;
00636             t  = bs_read( s, 2 ) << 6;
00637             i_processed_length += 4;
00638         }
00639 
00640         /* We are not entirely compliant here as full transparency is indicated
00641          * with a luma value of zero, not a transparency value of 0xff
00642          * (full transparency would actually be 0xff + 1). */
00643         if( y == 0 )
00644         {
00645             cr = cb = 0;
00646             t  = 0xff;
00647         }
00648 
00649         /* According to EN 300-743 section 7.2.3 note 1, type should
00650          * not have more than 1 bit set to one, but some streams don't
00651          * respect this note. */
00652         if( i_type & 0x04 && i_id < 4 )
00653         {
00654             p_clut->c_2b[i_id].Y = y;
00655             p_clut->c_2b[i_id].Cr = cr;
00656             p_clut->c_2b[i_id].Cb = cb;
00657             p_clut->c_2b[i_id].T = t;
00658         }
00659         if( i_type & 0x02 && i_id < 16 )
00660         {
00661             p_clut->c_4b[i_id].Y = y;
00662             p_clut->c_4b[i_id].Cr = cr;
00663             p_clut->c_4b[i_id].Cb = cb;
00664             p_clut->c_4b[i_id].T = t;
00665         }
00666         if( i_type & 0x01 )
00667         {
00668             p_clut->c_8b[i_id].Y = y;
00669             p_clut->c_8b[i_id].Cr = cr;
00670             p_clut->c_8b[i_id].Cb = cb;
00671             p_clut->c_8b[i_id].T = t;
00672         }
00673     }
00674 }
00675 
00676 static void decode_page_composition( decoder_t *p_dec, bs_t *s )
00677 {
00678     decoder_sys_t *p_sys = p_dec->p_sys;
00679     int i_version, i_state, i_segment_length, i_timeout, i;
00680 
00681     /* A page is composed by 0 or more region */
00682     i_segment_length = bs_read( s, 16 );
00683     i_timeout = bs_read( s, 8 );
00684     i_version = bs_read( s, 4 );
00685     i_state = bs_read( s, 2 );
00686     bs_skip( s, 2 ); /* Reserved */
00687 
00688     if( i_state == DVBSUB_PCS_STATE_CHANGE )
00689     {
00690         /* End of an epoch, reset decoder buffer */
00691 #ifdef DEBUG_DVBSUB
00692         msg_Dbg( p_dec, "page composition mode change" );
00693 #endif
00694         free_all( p_dec );
00695     }
00696     else if( !p_sys->p_page && i_state != DVBSUB_PCS_STATE_ACQUISITION &&
00697              i_state != DVBSUB_PCS_STATE_CHANGE )
00698     {
00699         /* Not a full PCS, we need to wait for one */
00700         msg_Dbg( p_dec, "didn't receive an acquisition page yet" );
00701 
00702 #if 0
00703         /* Try to start decoding even without an acquisition page */
00704         bs_skip( s,  8 * (i_segment_length - 2) );
00705         return;
00706 #endif
00707     }
00708 
00709 #ifdef DEBUG_DVBSUB
00710     if( i_state == DVBSUB_PCS_STATE_ACQUISITION )
00711         msg_Dbg( p_dec, "acquisition page composition" );
00712 #endif
00713 
00714     /* Check version number */
00715     if( p_sys->p_page && p_sys->p_page->i_version == i_version )
00716     {
00717         bs_skip( s,  8 * (i_segment_length - 2) );
00718         return;
00719     }
00720     else if( p_sys->p_page )
00721     {
00722         if( p_sys->p_page->i_region_defs )
00723             free( p_sys->p_page->p_region_defs );
00724         p_sys->p_page->i_region_defs = 0;
00725     }
00726 
00727     if( !p_sys->p_page )
00728     {
00729 #ifdef DEBUG_DVBSUB
00730         msg_Dbg( p_dec, "new page" );
00731 #endif
00732         /* Allocate a new page */
00733         p_sys->p_page = malloc( sizeof(dvbsub_page_t) );
00734     }
00735 
00736     p_sys->p_page->i_version = i_version;
00737     p_sys->p_page->i_timeout = i_timeout;
00738     p_sys->b_page = VLC_TRUE;
00739 
00740     /* Number of regions */
00741     p_sys->p_page->i_region_defs = (i_segment_length - 2) / 6;
00742 
00743     if( p_sys->p_page->i_region_defs == 0 ) return;
00744 
00745     p_sys->p_page->p_region_defs =
00746         malloc( p_sys->p_page->i_region_defs * sizeof(dvbsub_region_t) );
00747     for( i = 0; i < p_sys->p_page->i_region_defs; i++ )
00748     {
00749         p_sys->p_page->p_region_defs[i].i_id = bs_read( s, 8 );
00750         bs_skip( s, 8 ); /* Reserved */
00751         p_sys->p_page->p_region_defs[i].i_x = bs_read( s, 16 );
00752         p_sys->p_page->p_region_defs[i].i_y = bs_read( s, 16 );
00753 
00754 #ifdef DEBUG_DVBSUB
00755         msg_Dbg( p_dec, "page_composition, region %i (%i,%i)",
00756                  i, p_sys->p_page->p_region_defs[i].i_x,
00757                  p_sys->p_page->p_region_defs[i].i_y );
00758 #endif
00759     }
00760 }
00761 
00762 static void decode_region_composition( decoder_t *p_dec, bs_t *s )
00763 {
00764     decoder_sys_t *p_sys = p_dec->p_sys;
00765     dvbsub_region_t *p_region, **pp_region = &p_sys->p_regions;
00766     int i_segment_length, i_processed_length, i_id, i_version;
00767     int i_width, i_height, i_level_comp, i_depth, i_clut;
00768     int i_8_bg, i_4_bg, i_2_bg;
00769     vlc_bool_t b_fill;
00770 
00771     i_segment_length = bs_read( s, 16 );
00772     i_id = bs_read( s, 8 );
00773     i_version = bs_read( s, 4 );
00774 
00775     /* Check if we already have this region */
00776     for( p_region = p_sys->p_regions; p_region != NULL;
00777          p_region = p_region->p_next )
00778     {
00779         pp_region = &p_region->p_next;
00780         if( p_region->i_id == i_id ) break;
00781     }
00782 
00783     /* Check version number */
00784     if( p_region && p_region->i_version == i_version )
00785     {
00786         bs_skip( s, 8 * (i_segment_length - 1) - 4 );
00787         return;
00788     }
00789 
00790     if( !p_region )
00791     {
00792 #ifdef DEBUG_DVBSUB
00793         msg_Dbg( p_dec, "new region: %i", i_id );
00794 #endif
00795         p_region = *pp_region = malloc( sizeof(dvbsub_region_t) );
00796         memset( p_region, 0, sizeof(dvbsub_region_t) );
00797         p_region->p_object_defs = NULL;
00798         p_region->p_pixbuf = NULL;
00799         p_region->p_next = NULL;
00800     }
00801 
00802     /* Region attributes */
00803     p_region->i_id = i_id;
00804     p_region->i_version = i_version;
00805     b_fill = bs_read( s, 1 );
00806     bs_skip( s, 3 ); /* Reserved */
00807 
00808     i_width = bs_read( s, 16 );
00809     i_height = bs_read( s, 16 );
00810 #ifdef DEBUG_DVBSUB
00811     msg_Dbg( p_dec, " width=%d height=%d", i_width, i_height );
00812 #endif
00813     i_level_comp = bs_read( s, 3 );
00814     i_depth = bs_read( s, 3 );
00815     bs_skip( s, 2 ); /* Reserved */
00816     i_clut = bs_read( s, 8 );
00817 
00818     i_8_bg = bs_read( s, 8 );
00819     i_4_bg = bs_read( s, 4 );
00820     i_2_bg = bs_read( s, 2 );
00821     bs_skip( s, 2 ); /* Reserved */
00822 
00823     /* Free old object defs */
00824     while( p_region->i_object_defs )
00825     {
00826         int i = p_region->i_object_defs - 1;
00827         if( p_region->p_object_defs[i].psz_text )
00828             free( p_region->p_object_defs[i].psz_text );
00829         if( !i ) free( p_region->p_object_defs );
00830 
00831         p_region->i_object_defs--;
00832     }
00833     p_region->p_object_defs = NULL;
00834 
00835     /* Extra sanity checks */
00836     if( p_region->i_width != i_width || p_region->i_height != i_height )
00837     {
00838         if( p_region->p_pixbuf )
00839         {
00840             msg_Dbg( p_dec, "region size changed (not allowed)" );
00841             free( p_region->p_pixbuf );
00842         }
00843 
00844         p_region->p_pixbuf = malloc( i_height * i_width );
00845         p_region->i_depth = 0;
00846         b_fill = VLC_TRUE;
00847     }
00848     if( p_region->i_depth && (p_region->i_depth != i_depth ||
00849         p_region->i_level_comp != i_level_comp || p_region->i_clut != i_clut) )
00850     {
00851         msg_Dbg( p_dec, "region parameters changed (not allowed)" );
00852     }
00853 
00854     /* Erase background of region */
00855     if( b_fill )
00856     {
00857         int i_background = (p_region->i_depth == 1) ? i_2_bg :
00858             (p_region->i_depth == 2) ? i_4_bg : i_8_bg;
00859         memset( p_region->p_pixbuf, i_background, i_width * i_height );
00860     }
00861 
00862     p_region->i_width = i_width;
00863     p_region->i_height = i_height;
00864     p_region->i_level_comp = i_level_comp;
00865     p_region->i_depth = i_depth;
00866     p_region->i_clut = i_clut;
00867 
00868     /* List of objects in the region */
00869     i_processed_length = 10;
00870     while( i_processed_length < i_segment_length )
00871     {
00872         dvbsub_objectdef_t *p_obj;
00873 
00874         /* We create a new object */
00875         p_region->i_object_defs++;
00876         p_region->p_object_defs =
00877             realloc( p_region->p_object_defs,
00878                      sizeof(dvbsub_objectdef_t) * p_region->i_object_defs );
00879 
00880         /* We parse object properties */
00881         p_obj = &p_region->p_object_defs[p_region->i_object_defs - 1];
00882         p_obj->i_id         = bs_read( s, 16 );
00883         p_obj->i_type       = bs_read( s, 2 );
00884         bs_skip( s, 2 ); /* Provider */
00885         p_obj->i_x          = bs_read( s, 12 );
00886         bs_skip( s, 4 ); /* Reserved */
00887         p_obj->i_y          = bs_read( s, 12 );
00888         p_obj->psz_text     = 0;
00889 
00890         i_processed_length += 6;
00891 
00892         if( p_obj->i_type == DVBSUB_OT_BASIC_CHAR ||
00893             p_obj->i_type == DVBSUB_OT_COMPOSITE_STRING )
00894         {
00895             p_obj->i_fg_pc =  bs_read( s, 8 );
00896             p_obj->i_bg_pc =  bs_read( s, 8 );
00897             i_processed_length += 2;
00898         }
00899     }
00900 }
00901 
00902 static void dvbsub_render_pdata( decoder_t *, dvbsub_region_t *, int, int,
00903                                  uint8_t *, int );
00904 static void dvbsub_pdata2bpp( bs_t *, uint8_t *, int, int * );
00905 static void dvbsub_pdata4bpp( bs_t *, uint8_t *, int, int * );
00906 static void dvbsub_pdata8bpp( bs_t *, uint8_t *, int, int * );
00907 
00908 static void decode_object( decoder_t *p_dec, bs_t *s )
00909 {
00910     decoder_sys_t *p_sys = p_dec->p_sys;
00911     dvbsub_region_t *p_region;
00912     int i_segment_length, i_coding_method, i_version, i_id, i;
00913     vlc_bool_t b_non_modify_color;
00914 
00915     /* ETSI 300-743 paragraph 7.2.4
00916      * sync_byte, segment_type and page_id have already been processed.
00917      */
00918     i_segment_length = bs_read( s, 16 );
00919     i_id             = bs_read( s, 16 );
00920     i_version        = bs_read( s, 4 );
00921     i_coding_method  = bs_read( s, 2 );
00922 
00923     if( i_coding_method > 1 )
00924     {
00925         msg_Dbg( p_dec, "Unknown DVB subtitling coding %d is not handled!", i_coding_method );
00926         bs_skip( s, 8 * (i_segment_length - 2) - 6 );
00927         return;
00928     }
00929 
00930     /* Check if the object needs to be rendered in at least one
00931      * of the regions */
00932     for( p_region = p_sys->p_regions; p_region != NULL;
00933          p_region = p_region->p_next )
00934     {
00935         for( i = 0; i < p_region->i_object_defs; i++ )
00936             if( p_region->p_object_defs[i].i_id == i_id ) break;
00937 
00938         if( i != p_region->i_object_defs ) break;
00939     }
00940     if( !p_region )
00941     {
00942         bs_skip( s, 8 * (i_segment_length - 2) - 6 );
00943         return;
00944     }
00945 
00946 #ifdef DEBUG_DVBSUB
00947     msg_Dbg( p_dec, "new object: %i", i_id );
00948 #endif
00949 
00950     b_non_modify_color = bs_read( s, 1 );
00951     bs_skip( s, 1 ); /* Reserved */
00952 
00953     if( i_coding_method == 0x00 )
00954     {
00955         int i_topfield, i_bottomfield;
00956         uint8_t *p_topfield, *p_bottomfield;
00957 
00958         i_topfield    = bs_read( s, 16 );
00959         i_bottomfield = bs_read( s, 16 );
00960         p_topfield    = s->p_start + bs_pos( s ) / 8;
00961         p_bottomfield = p_topfield + i_topfield;
00962 
00963         bs_skip( s, 8 * (i_segment_length - 7) );
00964 
00965         /* Sanity check */
00966         if( i_segment_length < i_topfield + i_bottomfield + 7 ||
00967             p_topfield + i_topfield + i_bottomfield > s->p_end )
00968         {
00969             msg_Dbg( p_dec, "corrupted object data" );
00970             return;
00971         }
00972 
00973         for( p_region = p_sys->p_regions; p_region != NULL;
00974              p_region = p_region->p_next )
00975         {
00976             for( i = 0; i < p_region->i_object_defs; i++ )
00977             {
00978                 if( p_region->p_object_defs[i].i_id != i_id ) continue;
00979 
00980                 dvbsub_render_pdata( p_dec, p_region,
00981                                      p_region->p_object_defs[i].i_x,
00982                                      p_region->p_object_defs[i].i_y,
00983                                      p_topfield, i_topfield );
00984 
00985                 if( i_bottomfield )
00986                 {
00987                     dvbsub_render_pdata( p_dec, p_region,
00988                                          p_region->p_object_defs[i].i_x,
00989                                          p_region->p_object_defs[i].i_y + 1,
00990                                          p_bottomfield, i_bottomfield );
00991                 }
00992                 else
00993                 {
00994                     /* Duplicate the top field */
00995                     dvbsub_render_pdata( p_dec, p_region,
00996                                          p_region->p_object_defs[i].i_x,
00997                                          p_region->p_object_defs[i].i_y + 1,
00998                                          p_topfield, i_topfield );
00999                 }
01000             }
01001         }
01002     }
01003     else
01004     {
01005         /* DVB subtitling as characters */
01006         int i_number_of_codes = bs_read( s, 8 );
01007         uint8_t* p_start = s->p_start + bs_pos( s ) / 8;
01008 
01009         /* Sanity check */
01010         if( i_segment_length <  i_number_of_codes*2 + 4 ||
01011             p_start + i_number_of_codes*2 > s->p_end )
01012         {
01013             msg_Dbg( p_dec, "corrupted object data" );
01014             return;
01015         }
01016 
01017         for( p_region = p_sys->p_regions; p_region != NULL;
01018              p_region = p_region->p_next )
01019         {
01020             for( i = 0; i < p_region->i_object_defs; i++ )
01021             {
01022                 int j;
01023 
01024                 if( p_region->p_object_defs[i].i_id != i_id ) continue;
01025 
01026                 p_region->p_object_defs[i].psz_text =
01027                     realloc( p_region->p_object_defs[i].psz_text,
01028                              i_number_of_codes + 1 );
01029 
01030                 for( j = 0; j < i_number_of_codes; j++ )
01031                 {
01032                     p_region->p_object_defs[i].psz_text[j] = bs_read( s, 16 );
01033                 }
01034                 p_region->p_object_defs[i].psz_text[j] = 0;
01035             }
01036         }
01037     }
01038 
01039 #ifdef DEBUG_DVBSUB
01040     msg_Dbg( p_dec, "end object: %i", i_id );
01041 #endif
01042 }
01043 
01044 static void dvbsub_render_pdata( decoder_t *p_dec, dvbsub_region_t *p_region,
01045                                  int i_x, int i_y,
01046                                  uint8_t *p_field, int i_field )
01047 {
01048     uint8_t *p_pixbuf;
01049     int i_offset = 0;
01050     bs_t bs;
01051 
01052     /* Sanity check */
01053     if( !p_region->p_pixbuf )
01054     {
01055         msg_Err( p_dec, "region %i has no pixel buffer!", p_region->i_id );
01056         return;
01057     }
01058     if( i_y < 0 || i_x < 0 || i_y >= p_region->i_height ||
01059         i_x >= p_region->i_width )
01060     {
01061         msg_Dbg( p_dec, "invalid offset (%i,%i)", i_x, i_y );
01062         return;
01063     }
01064 
01065     p_pixbuf = p_region->p_pixbuf + i_y * p_region->i_width;
01066     bs_init( &bs, p_field, i_field );
01067 
01068     while( !bs_eof( &bs ) )
01069     {
01070         /* Sanity check */
01071         if( i_y >= p_region->i_height ) return;
01072 
01073         switch( bs_read( &bs, 8 ) )
01074         {
01075         case 0x10:
01076             dvbsub_pdata2bpp( &bs, p_pixbuf + i_x, p_region->i_width - i_x,
01077                               &i_offset );
01078             break;
01079 
01080         case 0x11:
01081             dvbsub_pdata4bpp( &bs, p_pixbuf + i_x, p_region->i_width - i_x,
01082                               &i_offset );
01083             break;
01084 
01085         case 0x12:
01086             dvbsub_pdata8bpp( &bs, p_pixbuf + i_x, p_region->i_width - i_x,
01087                               &i_offset );
01088             break;
01089 
01090         case 0x20:
01091         case 0x21:
01092         case 0x22:
01093             /* We don't use map tables */
01094             break;
01095 
01096         case 0xf0: /* End of line code */
01097             p_pixbuf += 2*p_region->i_width;
01098             i_offset = 0; i_y += 2;
01099             break;
01100         }
01101     }
01102 }
01103 
01104 static void dvbsub_pdata2bpp( bs_t *s, uint8_t *p, int i_width, int *pi_off )
01105 {
01106     vlc_bool_t b_stop = 0;
01107 
01108     while( !b_stop && !bs_eof( s ) )
01109     {
01110         int i_count = 0, i_color = 0;
01111 
01112         if( (i_color = bs_read( s, 2 )) != 0x00 )
01113         {
01114             i_count = 1;
01115         }
01116         else
01117         {
01118             if( bs_read( s, 1 ) == 0x01 )         // Switch1
01119             {
01120                 i_count = 3 + bs_read( s, 3 );
01121                 i_color = bs_read( s, 2 );
01122             }
01123             else
01124             {
01125                 if( bs_read( s, 1 ) == 0x00 )     //Switch2
01126                 {
01127                     switch( bs_read( s, 2 ) )     //Switch3
01128                     {
01129                     case 0x00:
01130                         b_stop = 1;
01131                         break;
01132                     case 0x01:
01133                         i_count = 2;
01134                         break;
01135                     case 0x02:
01136                         i_count =  12 + bs_read( s, 4 );
01137                         i_color = bs_read( s, 2 );
01138                         break;
01139                     case 0x03:
01140                         i_count =  29 + bs_read( s, 8 );
01141                         i_color = bs_read( s, 2 );
01142                         break;
01143                     default:
01144                         break;
01145                     }
01146                 }
01147                 else
01148                 {
01149                     /* 1 pixel color 0 */
01150                     i_count = 1;
01151                 }
01152             }
01153         }
01154 
01155         if( !i_count ) continue;
01156 
01157         /* Sanity check */
01158         if( i_count + *pi_off > i_width ) break;
01159 
01160         if( i_count == 1 ) p[*pi_off] = i_color;
01161         else memset( p + *pi_off, i_color, i_count );
01162 
01163         (*pi_off) += i_count;
01164     }
01165 
01166     bs_align( s );
01167 }
01168 
01169 static void dvbsub_pdata4bpp( bs_t *s, uint8_t *p, int i_width, int *pi_off )
01170 {
01171     vlc_bool_t b_stop = 0;
01172 
01173     while( !b_stop && !bs_eof( s ) )
01174     {
01175         int i_count = 0, i_color = 0;
01176 
01177         if( (i_color = bs_read( s, 4 )) != 0x00 )
01178         {
01179             /* Add 1 pixel */
01180             i_count = 1;
01181         }
01182         else
01183         {
01184             if( bs_read( s, 1 ) == 0x00 )           // Switch1
01185             {
01186                 if( bs_show( s, 3 ) != 0x00 )
01187                 {
01188                     i_count = 2 + bs_read( s, 3 );
01189                 }
01190                 else
01191                 {
01192                     bs_skip( s, 3 );
01193                     b_stop = 1;
01194                 }
01195             }
01196             else
01197             {
01198                 if( bs_read( s, 1 ) == 0x00)        //Switch2
01199                 {
01200                     i_count =  4 + bs_read( s, 2 );
01201                     i_color = bs_read( s, 4 );
01202                 }
01203                 else
01204                 {
01205                     switch ( bs_read( s, 2 ) )     //Switch3
01206                     {
01207                     case 0x0:
01208                         i_count = 1;
01209                         break;
01210                     case 0x1:
01211                         i_count = 2;
01212                         break;
01213                     case 0x2:
01214                         i_count = 9 + bs_read( s, 4 );
01215                         i_color = bs_read( s, 4 );
01216                         break;
01217                     case 0x3:
01218                         i_count= 25 + bs_read( s, 8 );
01219                         i_color = bs_read( s, 4 );
01220                         break;
01221                     }
01222                 }
01223             }
01224         }
01225 
01226         if( !i_count ) continue;
01227 
01228         /* Sanity check */
01229         if( i_count + *pi_off > i_width ) break;
01230 
01231         if( i_count == 1 ) p[*pi_off] = i_color;
01232         else memset( p + *pi_off, i_color, i_count );
01233 
01234         (*pi_off) += i_count;
01235     }
01236 
01237     bs_align( s );
01238 }
01239 
01240 static void dvbsub_pdata8bpp( bs_t *s, uint8_t *p, int i_width, int *pi_off )
01241 {
01242     vlc_bool_t b_stop = 0;
01243 
01244     while( !b_stop && !bs_eof( s ) )
01245     {
01246         int i_count = 0, i_color = 0;
01247 
01248         if( (i_color = bs_read( s, 8 )) != 0x00 )
01249         {
01250             /* Add 1 pixel */
01251             i_count = 1;
01252         }
01253         else
01254         {
01255             if( bs_read( s, 1 ) == 0x00 )           // Switch1
01256             {
01257                 if( bs_show( s, 7 ) != 0x00 )
01258                 {
01259                     i_count = bs_read( s, 7 );
01260                 }
01261                 else
01262                 {
01263                     bs_skip( s, 7 );
01264                     b_stop = 1;
01265                 }
01266             }
01267             else
01268             {
01269                 i_count = bs_read( s, 7 );
01270                 i_color = bs_read( s, 8 );
01271             }
01272         }
01273 
01274         if( !i_count ) continue;
01275 
01276         /* Sanity check */
01277         if( i_count + *pi_off > i_width ) break;
01278 
01279         if( i_count == 1 ) p[*pi_off] = i_color;
01280         else memset( p + *pi_off, i_color, i_count );
01281 
01282         (*pi_off) += i_count;
01283     }
01284 
01285     bs_align( s );
01286 }
01287 
01288 static void free_all( decoder_t *p_dec )
01289 {
01290     decoder_sys_t *p_sys = p_dec->p_sys;
01291     dvbsub_region_t *p_reg, *p_reg_next;
01292     dvbsub_clut_t *p_clut, *p_clut_next;
01293 
01294     for( p_clut = p_sys->p_cluts; p_clut != NULL; p_clut = p_clut_next )
01295     {
01296         p_clut_next = p_clut->p_next;
01297         free( p_clut );
01298     }
01299     p_sys->p_cluts = NULL;
01300 
01301     for( p_reg = p_sys->p_regions; p_reg != NULL; p_reg = p_reg_next )
01302     {
01303         int i;
01304 
01305         p_reg_next = p_reg->p_next;
01306         for( i = 0; i < p_reg->i_object_defs; i++ )
01307             if( p_reg->p_object_defs[i].psz_text )
01308                 free( p_reg->p_object_defs[i].psz_text );
01309         if( p_reg->i_object_defs ) free( p_reg->p_object_defs );
01310         if( p_reg->p_pixbuf ) free( p_reg->p_pixbuf );
01311         free( p_reg );
01312     }
01313     p_sys->p_regions = NULL;
01314 
01315     if( p_sys->p_page )
01316     {
01317         if( p_sys->p_page->i_region_defs )
01318             free( p_sys->p_page->p_region_defs );
01319         free( p_sys->p_page );
01320     }
01321     p_sys->p_page = NULL;
01322 }
01323 
01324 static subpicture_t *render( decoder_t *p_dec )
01325 {
01326     decoder_sys_t *p_sys = p_dec->p_sys;
01327     subpicture_t *p_spu;
01328     subpicture_region_t **pp_spu_region;
01329     int i, j, i_timeout = 0;
01330 
01331     /* Allocate the subpicture internal data. */
01332     p_spu = p_dec->pf_spu_buffer_new( p_dec );
01333     if( !p_spu ) return NULL;
01334 
01335     pp_spu_region = &p_spu->p_region;
01336 
01337     /* Loop on region definitions */
01338 #ifdef DEBUG_DVBSUB
01339     if( p_sys->p_page )
01340         msg_Dbg( p_dec, "rendering %i regions", p_sys->p_page->i_region_defs );
01341 #endif
01342 
01343     for( i = 0; p_sys->p_page && i < p_sys->p_page->i_region_defs; i++ )
01344     {
01345         dvbsub_region_t     *p_region;
01346         dvbsub_regiondef_t  *p_regiondef;
01347         dvbsub_clut_t       *p_clut;
01348         dvbsub_color_t      *p_color;
01349         subpicture_region_t *p_spu_region;
01350         uint8_t *p_src, *p_dst;
01351         video_format_t fmt;
01352         int i_pitch;
01353 
01354         i_timeout = p_sys->p_page->i_timeout;
01355 
01356         p_regiondef = &p_sys->p_page->p_region_defs[i];
01357 
01358 #ifdef DEBUG_DVBSUB
01359         msg_Dbg( p_dec, "rendering region %i (%i,%i)", i,
01360                  p_regiondef->i_x, p_regiondef->i_y );
01361 #endif
01362 
01363         /* Find associated region */
01364         for( p_region = p_sys->p_regions; p_region != NULL;
01365              p_region = p_region->p_next )
01366         {
01367             if( p_regiondef->i_id == p_region->i_id ) break;
01368         }
01369 
01370         if( !p_region )
01371         {
01372             msg_Dbg( p_dec, "region %i not found", p_regiondef->i_id );
01373             continue;
01374         }
01375 
01376         /* Find associated CLUT */
01377         for( p_clut = p_sys->p_cluts; p_clut != NULL; p_clut = p_clut->p_next )
01378         {
01379             if( p_region->i_clut == p_clut->i_id ) break;
01380         }
01381         if( !p_clut )
01382         {
01383             msg_Dbg( p_dec, "clut %i not found", p_region->i_clut );
01384             continue;
01385         }
01386 
01387         /* Create new SPU region */
01388         memset( &fmt, 0, sizeof(video_format_t) );
01389         fmt.i_chroma = VLC_FOURCC('Y','U','V','P');
01390         fmt.i_aspect = 0; /* 0 means use aspect ratio of background video */
01391         fmt.i_width = fmt.i_visible_width = p_region->i_width;
01392         fmt.i_height = fmt.i_visible_height = p_region->i_height;
01393         fmt.i_x_offset = fmt.i_y_offset = 0;
01394         p_spu_region = p_spu->pf_create_region( VLC_OBJECT(p_dec), &fmt );
01395         if( !p_spu_region )
01396         {
01397             msg_Err( p_dec, "cannot allocate SPU region" );
01398             continue;
01399         }
01400         p_spu_region->i_x = p_regiondef->i_x;
01401         p_spu_region->i_y = p_regiondef->i_y;
01402         *pp_spu_region = p_spu_region;
01403         pp_spu_region = &p_spu_region->p_next;
01404 
01405         /* Build palette */
01406         fmt.p_palette->i_entries = p_region->i_depth == 1 ? 4 :
01407             p_region->i_depth == 2 ? 16 : 256;
01408         p_color = (p_region->i_depth == 1) ? p_clut->c_2b :
01409             (p_region->i_depth == 2) ? p_clut->c_4b : p_clut->c_8b;
01410         for( j = 0; j < fmt.p_palette->i_entries; j++ )
01411         {
01412             fmt.p_palette->palette[j][0] = p_color[j].Y;
01413             fmt.p_palette->palette[j][1] = p_color[j].Cr;
01414             fmt.p_palette->palette[j][2] = p_color[j].Cb;
01415             fmt.p_palette->palette[j][3] = 0xff - p_color[j].T;
01416         }
01417 
01418         p_src = p_region->p_pixbuf;
01419         p_dst = p_spu_region->picture.Y_PIXELS;
01420         i_pitch = p_spu_region->picture.Y_PITCH;
01421 
01422         /* Copy pixel buffer */
01423         for( j = 0; j < p_region->i_height; j++ )
01424         {
01425             memcpy( p_dst, p_src, p_region->i_width );
01426             p_src += p_region->i_width;
01427             p_dst += i_pitch;
01428         }
01429 
01430         /* Check subtitles encoded as strings of characters
01431          * (since there are not rendered in the pixbuffer) */
01432         for( j = 0; j < p_region->i_object_defs; j++ )
01433         {
01434             dvbsub_objectdef_t *p_object_def = &p_region->p_object_defs[j];
01435 
01436             if( p_object_def->i_type != 1 || !p_object_def->psz_text )
01437                 continue;
01438 
01439             /* Create new SPU region */
01440             memset( &fmt, 0, sizeof(video_format_t) );
01441             fmt.i_chroma = VLC_FOURCC('T','E','X','T');
01442             fmt.i_aspect = VOUT_ASPECT_FACTOR;
01443             fmt.i_width = fmt.i_visible_width = p_region->i_width;
01444             fmt.i_height = fmt.i_visible_height = p_region->i_height;
01445             fmt.i_x_offset = fmt.i_y_offset = 0;
01446             p_spu_region = p_spu->pf_create_region( VLC_OBJECT(p_dec), &fmt );
01447             if( !p_region )
01448             {
01449                 msg_Err( p_dec, "cannot allocate SPU region" );
01450                 continue;
01451             }
01452 
01453             p_spu_region->psz_text = strdup( p_object_def->psz_text );
01454             p_spu_region->i_x = p_regiondef->i_x + p_object_def->i_x;
01455             p_spu_region->i_y = p_regiondef->i_y + p_object_def->i_y;
01456             *pp_spu_region = p_spu_region;
01457             pp_spu_region = &p_spu_region->p_next;
01458         }
01459     }
01460 
01461     /* Set the pf_render callback */
01462     p_spu->i_start = p_sys->i_pts;
01463     p_spu->i_stop = p_spu->i_start + (mtime_t) (i_timeout * 1000000);
01464     p_spu->b_ephemer = VLC_TRUE;
01465     p_spu->b_fade = VLC_TRUE;
01466 
01467     /* Correct positioning of SPU */
01468     p_spu->b_absolute = p_sys->b_absolute;
01469     p_spu->i_flags = p_sys->i_spu_position;
01470     p_spu->i_x = p_sys->i_spu_x;
01471     p_spu->i_y = p_sys->i_spu_y;
01472 
01473     return p_spu;
01474 }
01475 
01476 /*****************************************************************************
01477  * encoder_sys_t : encoder descriptor
01478  *****************************************************************************/
01479 typedef struct encoder_region_t
01480 {
01481     int i_width;
01482     int i_height;
01483 
01484 } encoder_region_t;
01485 
01486 struct encoder_sys_t
01487 {
01488     unsigned int i_page_ver;
01489     unsigned int i_region_ver;
01490     unsigned int i_clut_ver;
01491 
01492     int i_regions;
01493     encoder_region_t *p_regions;
01494 
01495     mtime_t i_pts;
01496 
01497     /* subpicture positioning */
01498     int i_offset_x;
01499     int i_offset_y;
01500     int i_timeout_delay;
01501 };
01502 
01503 static void encode_page_composition( encoder_t *, bs_t *, subpicture_t * );
01504 static void encode_clut( encoder_t *, bs_t *, subpicture_t * );
01505 static void encode_region_composition( encoder_t *, bs_t *, subpicture_t * );
01506 static void encode_object( encoder_t *, bs_t *, subpicture_t * );
01507 
01508 /*****************************************************************************
01509  * OpenEncoder: probe the encoder and return score
01510  *****************************************************************************/
01511 static int OpenEncoder( vlc_object_t *p_this )
01512 {
01513     encoder_t *p_enc = (encoder_t *)p_this;
01514     encoder_sys_t *p_sys;
01515     vlc_value_t val;
01516 
01517     if( p_enc->fmt_out.i_codec != VLC_FOURCC('d','v','b','s') &&
01518         !p_enc->b_force )
01519     {
01520         return VLC_EGENERIC;
01521     }
01522 
01523     /* Allocate the memory needed to store the decoder's structure */
01524     if( ( p_sys = (encoder_sys_t *)malloc(sizeof(encoder_sys_t)) ) == NULL )
01525     {
01526         msg_Err( p_enc, "out of memory" );
01527         return VLC_ENOMEM;
01528     }
01529     p_enc->p_sys = p_sys;
01530 
01531     p_enc->pf_encode_sub = Encode;
01532     p_enc->fmt_out.i_codec = VLC_FOURCC('d','v','b','s');
01533     p_enc->fmt_out.subs.dvb.i_id  = 1 << 16 | 1;
01534 
01535     sout_CfgParse( p_enc, ENC_CFG_PREFIX, ppsz_enc_options, p_enc->p_cfg );
01536 
01537     p_sys->i_page_ver = 0;
01538     p_sys->i_region_ver = 0;
01539     p_sys->i_clut_ver = 0;
01540     p_sys->i_regions = 0;
01541     p_sys->p_regions = 0;
01542 
01543     var_Create( p_this, ENC_CFG_PREFIX "x", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
01544     var_Get( p_this, ENC_CFG_PREFIX "x", &val );
01545     p_sys->i_offset_x = val.i_int;
01546     var_Create( p_this, ENC_CFG_PREFIX "y", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
01547     var_Get( p_this, ENC_CFG_PREFIX "y", &val );
01548     p_sys->i_offset_y = val.i_int;
01549     var_Create( p_this, ENC_CFG_PREFIX "timeout", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
01550     var_Get( p_this, ENC_CFG_PREFIX "timeout", &val );
01551     p_sys->i_timeout_delay = val.i_int;
01552 
01553     return VLC_SUCCESS;
01554 }
01555 
01556 /* FIXME: this routine is a hack to convert VLC_FOURCC('Y','U','V','A') 
01557  *        into VLC_FOURCC('Y','U','V','P')
01558  */
01559 static subpicture_t *YuvaYuvp( encoder_t *p_enc, subpicture_t *p_subpic )
01560 {
01561     subpicture_region_t *p_region = NULL;
01562 
01563     if( !p_subpic ) return NULL;
01564 
01565     for( p_region = p_subpic->p_region; p_region; p_region = p_region->p_next )
01566     {
01567         video_format_t *p_fmt = &p_region->fmt;
01568         int i = 0, j = 0, n = 0, p = 0;
01569         int i_max_entries = 256;
01570 
01571 #ifdef RANDOM_DITHERING
01572         int i_seed = 0xdeadbeef; /* random seed */
01573 #else
01574         int *pi_delta;
01575 #endif
01576         int i_pixels = p_region->picture.p[0].i_visible_lines
01577                         * p_region->picture.p[0].i_pitch;
01578         int i_iterator = p_region->picture.p[0].i_visible_lines * 3 / 4
01579                             * p_region->picture.p[0].i_pitch
01580                         + p_region->picture.p[0].i_pitch * 1 / 3;
01581         int i_tolerance = 0;
01582 
01583 #if DEBUG_DVBSUB
01584         msg_Dbg( p_enc, "YuvaYuvp: i_pixels=%d, i_iterator=%d", i_pixels, i_iterator );
01585 #endif
01586         p_fmt->i_chroma = VLC_FOURCC('Y','U','V','P');
01587         p_fmt->p_palette = (video_palette_t *) malloc( sizeof( video_palette_t ) );
01588         if( !p_fmt->p_palette ) break;
01589         p_fmt->p_palette->i_entries = 0;
01590 
01591         /* Find best iterator using Euclide’s algorithm */
01592         for( ; i_iterator > 1 ; i_iterator-- )
01593         {
01594             int a = i_pixels;
01595             int b = i_iterator;
01596             int c;
01597 
01598             while( b )
01599             {
01600                 c = a % b;
01601                 a = b;
01602                 b = c;
01603             }
01604 
01605             if( a == 1 )
01606             {
01607                 break;
01608             }
01609         }
01610 
01611         /* Count colors, build best palette */
01612         for( i_tolerance = 0; i_tolerance < 128; i_tolerance++ )
01613         {
01614             vlc_bool_t b_success = VLC_TRUE;
01615             p_fmt->p_palette->i_entries = 0;
01616 
01617             for( i = 0; i < i_pixels ; )
01618             {
01619                 uint8_t y, u, v, a;
01620                 y = p_region->picture.p[0].p_pixels[i];
01621                 u = p_region->picture.p[1].p_pixels[i];
01622                 v = p_region->picture.p[2].p_pixels[i];
01623                 a = p_region->picture.p[3].p_pixels[i];
01624                 for( j = 0; j < p_fmt->p_palette->i_entries; j++ )
01625                 {
01626                     if( abs((int)p_fmt->p_palette->palette[j][0] - (int)y) <= i_tolerance &&
01627                         abs((int)p_fmt->p_palette->palette[j][1] - (int)u) <= i_tolerance &&
01628                         abs((int)p_fmt->p_palette->palette[j][2] - (int)v) <= i_tolerance &&
01629                         abs((int)p_fmt->p_palette->palette[j][3] - (int)a) <= i_tolerance / 2 )
01630                     {
01631                         break;
01632                     }
01633                 }
01634                 if( j == p_fmt->p_palette->i_entries )
01635                 {
01636                     p_fmt->p_palette->palette[j][0] = y;
01637                     p_fmt->p_palette->palette[j][1] = u;
01638                     p_fmt->p_palette->palette[j][2] = v;
01639                     p_fmt->p_palette->palette[j][3] = a;
01640                     p_fmt->p_palette->i_entries++;
01641                 }
01642                 if( p_fmt->p_palette->i_entries >= i_max_entries )
01643                 {
01644                     b_success = VLC_FALSE;
01645                     break;
01646                 }
01647                 i += i_iterator;
01648                 if( i > i_pixels )
01649                 {
01650                     i -= i_pixels;
01651                 }
01652             }
01653 
01654             if( b_success )
01655             {
01656                 break;
01657             }
01658         }
01659 
01660 #if DEBUG_DVBSUB
01661         msg_Dbg( p_enc, "best palette has %d colors", p_fmt->p_palette->i_entries );
01662 #endif
01663 
01664 #ifndef RANDOM_DITHERING
01665         pi_delta = malloc( ( p_region->picture.p[0].i_pitch + 1 )
01666                             * sizeof(int) * 4  );
01667         for( i = 0; i < (p_region->picture.p[0].i_pitch + 1) * 4 ; i++ )
01668         {
01669             pi_delta[ i ] = 0;
01670         }
01671 #endif
01672 
01673         /* Fill image with our new colours */
01674         for( p = 0; p < p_region->picture.p[0].i_visible_lines ; p++ )
01675         {
01676             int i_ydelta = 0, i_udelta = 0, i_vdelta = 0, i_adelta = 0;
01677 
01678             for( n = 0; n < p_region->picture.p[0].i_pitch ; n++ )
01679             {
01680                 int i_offset = p * p_region->picture.p[0].i_pitch + n;
01681                 int y, u, v, a;
01682                 int i_mindist, i_best;
01683 
01684                 y = (int)p_region->picture.p[0].p_pixels[i_offset];
01685                 u = (int)p_region->picture.p[1].p_pixels[i_offset];
01686                 v = (int)p_region->picture.p[2].p_pixels[i_offset];
01687                 a = (int)p_region->picture.p[3].p_pixels[i_offset];
01688 
01689                 /* Add dithering compensation */
01690 #ifdef RANDOM_DITHERING
01691                 y += ((i_seed & 0xff) - 0x80) * i_tolerance / 0x80;
01692                 u += (((i_seed >> 8) & 0xff) - 0x80) * i_tolerance / 0x80;
01693                 v += (((i_seed >> 16) & 0xff) - 0x80) * i_tolerance / 0x80;
01694                 a += (((i_seed >> 24) & 0xff) - 0x80) * i_tolerance / 0x80;
01695 #else
01696                 y += i_ydelta + pi_delta[ n * 4 ];
01697                 u += i_udelta + pi_delta[ n * 4 + 1 ];
01698                 v += i_vdelta + pi_delta[ n * 4 + 2 ];
01699                 a += i_adelta + pi_delta[ n * 4 + 3 ];
01700 #endif
01701 
01702                 /* Find best colour in palette */
01703                 for( i_mindist = 99999999, i_best = 0, j = 0; j < p_fmt->p_palette->i_entries; j++ )
01704                 {
01705                     int i_dist = 0;
01706 
01707                     i_dist += abs((int)p_fmt->p_palette->palette[j][0] - y);
01708                     i_dist += abs((int)p_fmt->p_palette->palette[j][1] - u);
01709                     i_dist += abs((int)p_fmt->p_palette->palette[j][2] - v);
01710                     i_dist += 2 * abs((int)p_fmt->p_palette->palette[j][3] - a);
01711 
01712                     if( i_dist < i_mindist )
01713                     {
01714                         i_mindist = i_dist;
01715                         i_best = j;
01716                     }
01717                 }
01718 
01719                 /* Set pixel to best color */
01720                 p_region->picture.p[0].p_pixels[i_offset] = i_best;
01721 
01722                 /* Update dithering state */
01723 #ifdef RANDOM_DITHERING
01724                 i_seed = (i_seed * 0x1283837) ^ 0x789479 ^ (i_seed >> 13);
01725 #else
01726                 i_ydelta = y - (int)p_fmt->p_palette->palette[i_best][0];
01727                 i_udelta = u - (int)p_fmt->p_palette->palette[i_best][1];
01728                 i_vdelta = v - (int)p_fmt->p_palette->palette[i_best][2];
01729                 i_adelta = a - (int)p_fmt->p_palette->palette[i_best][3];
01730                 pi_delta[ n * 4 ] = i_ydelta * 3 / 8;
01731                 pi_delta[ n * 4 + 1 ] = i_udelta * 3 / 8;
01732                 pi_delta[ n * 4 + 2 ] = i_vdelta * 3 / 8;
01733                 pi_delta[ n * 4 + 3 ] = i_adelta * 3 / 8;
01734                 i_ydelta = i_ydelta * 5 / 8;
01735                 i_udelta = i_udelta * 5 / 8;
01736                 i_vdelta = i_vdelta * 5 / 8;
01737                 i_adelta = i_adelta * 5 / 8;
01738 #endif
01739             }
01740         }
01741 #ifndef RANDOM_DITHERING
01742         free( pi_delta );
01743 #endif
01744 
01745         /* pad palette */
01746         for( i = p_fmt->p_palette->i_entries; i < i_max_entries; i++ )
01747         {
01748             p_fmt->p_palette->palette[i][0] = 0;
01749             p_fmt->p_palette->palette[i][1] = 0;
01750             p_fmt->p_palette->palette[i][2] = 0;
01751             p_fmt->p_palette->palette[i][3] = 0;
01752         }
01753         p_fmt->p_palette->i_entries = i_max_entries;
01754 #if DEBUG_DVBSUB
01755         msg_Dbg( p_enc, "best palette has %d colors", p_fmt->p_palette->i_entries );
01756 #endif
01757     }
01758     return p_subpic;
01759 } /* End of hack */
01760 
01761 /****************************************************************************
01762  * Encode: the whole thing
01763  ****************************************************************************/
01764 static block_t *Encode( encoder_t *p_enc, subpicture_t *p_subpic )
01765 {
01766     subpicture_t *p_temp = NULL;
01767     subpicture_region_t *p_region = NULL;
01768     bs_t bits, *s = &bits;
01769     block_t *p_block;
01770 
01771     if( !p_subpic || !p_subpic->p_region ) return NULL;
01772 
01773     /* FIXME: this is a hack to convert VLC_FOURCC('Y','U','V','A') into
01774      *  VLC_FOURCC('Y','U','V','P')
01775      */
01776     p_region = p_subpic->p_region;
01777     if( p_region->fmt.i_chroma == VLC_FOURCC('Y','U','V','A') )
01778     {
01779         p_temp = YuvaYuvp( p_enc, p_subpic );
01780         if( !p_temp )
01781         {
01782             msg_Err( p_enc, "no picture in subpicture" );
01783             return NULL;
01784         }
01785         p_region = p_subpic->p_region;
01786     }
01787 
01788     /* Sanity check */
01789     if( !p_region ) return NULL;
01790 
01791     if( p_region->fmt.i_chroma != VLC_FOURCC('T','E','X','T') &&
01792         p_region->fmt.i_chroma != VLC_FOURCC('Y','U','V','P') ) return NULL;
01793 
01794     if( p_region->fmt.p_palette )
01795     {
01796         switch( p_region->fmt.p_palette->i_entries )
01797         {
01798             case 0:
01799             case 4:
01800             case 16:
01801             case 256:
01802                 break;
01803             default:
01804                 msg_Err( p_enc, "subpicture palette (%d) not handled",
01805                             p_region->fmt.p_palette->i_entries );
01806                 return NULL;
01807         }
01808     }
01809     /* End of hack */
01810 
01811 #if DEBUG_DVBSUB
01812     msg_Dbg( p_enc, "encoding subpicture" );
01813 #endif
01814     p_block = block_New( p_enc, 64000 );
01815     bs_init( s, p_block->p_buffer, p_block->i_buffer );
01816 
01817     bs_write( s, 8, 0x20 ); /* Data identifier */
01818     bs_write( s, 8, 0x0 );  /* Subtitle stream id */
01819 
01820     encode_page_composition( p_enc, s, p_subpic );
01821     encode_region_composition( p_enc, s, p_subpic );
01822     encode_clut( p_enc, s, p_subpic );
01823     encode_object( p_enc, s, p_subpic );
01824 
01825     /* End of display */
01826     bs_write( s, 8, 0x0f ); /* Sync byte */
01827     bs_write( s, 8, DVBSUB_ST_ENDOFDISPLAY ); /* Segment type */
01828     bs_write( s, 16, 1 );  /* Page id */
01829     bs_write( s, 16, 0 );  /* Segment length */
01830 
01831     bs_write( s, 8, 0xff );/* End marker */
01832     p_block->i_buffer = bs_pos( s ) / 8;
01833     p_block->i_pts = p_block->i_dts = p_subpic->i_start;
01834     if( !p_subpic->b_ephemer && p_subpic->i_stop > p_subpic->i_start )
01835     {
01836         block_t *p_block_stop;
01837 
01838         p_block->i_length = p_subpic->i_stop - p_subpic->i_start;
01839 
01840         /* Send another (empty) subtitle to signal the end of display */
01841         p_block_stop = block_New( p_enc, 64000 );
01842         bs_init( s, p_block_stop->p_buffer, p_block_stop->i_buffer );
01843         bs_write( s, 8, 0x20 ); /* Data identifier */
01844         bs_write( s, 8, 0x0 );  /* Subtitle stream id */
01845         encode_page_composition( p_enc, s, 0 );
01846         bs_write( s, 8, 0x0f ); /* Sync byte */
01847         bs_write( s, 8, DVBSUB_ST_ENDOFDISPLAY ); /* Segment type */
01848         bs_write( s, 16, 1 );  /* Page id */
01849         bs_write( s, 16, 0 );  /* Segment length */
01850         bs_write( s, 8, 0xff );/* End marker */
01851         p_block_stop->i_buffer = bs_pos( s ) / 8;
01852         p_block_stop->i_pts = p_block_stop->i_dts = p_subpic->i_stop;
01853         block_ChainAppend( &p_block, p_block_stop );
01854         p_block_stop->i_length = 100000; /* p_subpic->i_stop - p_subpic->i_start; */
01855     }
01856 #ifdef DEBUG_DVBSUB
01857     msg_Dbg( p_enc, "subpicture encoded properly" );
01858 #endif
01859     return p_block;
01860 }
01861 
01862 /*****************************************************************************
01863  * CloseEncoder: encoder destruction
01864  *****************************************************************************/
01865 static void CloseEncoder( vlc_object_t *p_this )
01866 {
01867     encoder_t *p_enc = (encoder_t *)p_this;
01868     encoder_sys_t *p_sys = p_enc->p_sys;
01869 
01870     var_Destroy( p_this , ENC_CFG_PREFIX "x" );
01871     var_Destroy( p_this , ENC_CFG_PREFIX "y" );
01872     var_Destroy( p_this , ENC_CFG_PREFIX "timeout" );
01873 
01874     if( p_sys->i_regions ) free( p_sys->p_regions );
01875     free( p_sys );
01876 }
01877 
01878 static void encode_page_composition( encoder_t *p_enc, bs_t *s,
01879                                      subpicture_t *p_subpic )
01880 {
01881     encoder_sys_t *p_sys = p_enc->p_sys;
01882     subpicture_region_t *p_region;
01883     vlc_bool_t b_mode_change = VLC_FALSE;
01884     int i_regions, i_timeout;
01885 
01886     bs_write( s, 8, 0x0f ); /* Sync byte */
01887     bs_write( s, 8, DVBSUB_ST_PAGE_COMPOSITION ); /* Segment type */
01888     bs_write( s, 16, 1 ); /* Page id */
01889 
01890     for( i_regions = 0, p_region = p_subpic ? p_subpic->p_region : 0;
01891          p_region; p_region = p_region->p_next, i_regions++ )
01892     {
01893         if( i_regions >= p_sys->i_regions )
01894         {
01895             encoder_region_t region;
01896             region.i_width = region.i_height = 0;
01897             p_sys->p_regions =
01898                 realloc( p_sys->p_regions, sizeof(encoder_region_t) *
01899                          (p_sys->i_regions + 1) );
01900             p_sys->p_regions[p_sys->i_regions++] = region;
01901         }
01902 
01903         if( ( p_sys->p_regions[i_regions].i_width <
01904               (int)p_region->fmt.i_visible_width ) || 
01905             ( p_sys->p_regions[i_regions].i_width >
01906               (int)p_region->fmt.i_visible_width ) )
01907         {
01908             b_mode_change = VLC_TRUE;
01909             msg_Dbg( p_enc, "region %i width change: %i -> %i",
01910                      i_regions, p_sys->p_regions[i_regions].i_width,
01911                      p_region->fmt.i_visible_width );
01912             p_sys->p_regions[i_regions].i_width =
01913                 p_region->fmt.i_visible_width;
01914         }
01915         if( ( p_sys->p_regions[i_regions].i_height <
01916              (int)p_region->fmt.i_visible_height ) ||
01917             ( p_sys->p_regions[i_regions].i_height >
01918               (int)p_region->fmt.i_visible_height ) )
01919         {
01920             b_mode_change = VLC_TRUE;
01921             msg_Dbg( p_enc, "region %i height change: %i -> %i",
01922                      i_regions, p_sys->p_regions[i_regions].i_height,
01923                      p_region->fmt.i_visible_height );
01924             p_sys->p_regions[i_regions].i_height =
01925                 p_region->fmt.i_visible_height;
01926         }
01927     }
01928 
01929     bs_write( s, 16, i_regions * 6 + 2 ); /* Segment length */
01930 
01931     i_timeout = 0;
01932     if( p_subpic && !p_subpic->b_ephemer &&
01933         p_subpic->i_stop > p_subpic->i_start )
01934     {
01935         i_timeout = (p_subpic->i_stop - p_subpic->i_start) / 1000000;
01936     }
01937 
01938     bs_write( s, 8, i_timeout + p_sys->i_timeout_delay ); /* Timeout */
01939     bs_write( s, 4, p_sys->i_page_ver++ );
01940     bs_write( s, 2, b_mode_change ?
01941               DVBSUB_PCS_STATE_CHANGE : DVBSUB_PCS_STATE_ACQUISITION );
01942     bs_write( s, 2, 0 ); /* Reserved */
01943 
01944     for( i_regions = 0, p_region = p_subpic ? p_subpic->p_region : 0;
01945          p_region; p_region = p_region->p_next, i_regions++ )
01946     {
01947         bs_write( s, 8, i_regions );
01948         bs_write( s, 8, 0 ); /* Reserved */
01949         if( (p_sys->i_offset_x > 0) && (p_sys->i_offset_y > 0) )
01950         {
01951             bs_write( s, 16, p_sys->i_offset_x ); /* override x position */
01952             bs_write( s, 16, p_sys->i_offset_y ); /* override y position */
01953         }
01954         else
01955         {
01956             bs_write( s, 16, p_region->i_x );
01957             bs_write( s, 16, p_region->i_y );
01958         }
01959     }
01960 }
01961 
01962 static void encode_clut( encoder_t *p_enc, bs_t *s, subpicture_t *p_subpic )
01963 {
01964     encoder_sys_t *p_sys = p_enc->p_sys;
01965     subpicture_region_t *p_region = p_subpic->p_region;
01966     video_palette_t *p_pal, pal;
01967     int i;
01968 
01969     /* Sanity check */
01970     if( !p_region ) return;
01971 
01972     if( p_region->fmt.i_chroma == VLC_FOURCC('Y','U','V','P') )
01973     {
01974         p_pal = p_region->fmt.p_palette;
01975     }
01976     else
01977     {
01978         pal.i_entries = 4;
01979         for( i = 0; i < 4; i++ )
01980         {
01981             pal.palette[i][0] = 0;
01982             pal.palette[i][1] = 0;
01983             pal.palette[i][2] = 0;
01984             pal.palette[i][3] = 0;
01985         }
01986         p_pal = &pal;
01987     }
01988 
01989     bs_write( s, 8, 0x0f ); /* Sync byte */
01990     bs_write( s, 8, DVBSUB_ST_CLUT_DEFINITION ); /* Segment type */
01991     bs_write( s, 16, 1 );  /* Page id */
01992 
01993     bs_write( s, 16, p_pal->i_entries * 6 + 2 ); /* Segment length */
01994     bs_write( s, 8, 1 ); /* Clut id */
01995     bs_write( s, 4, p_sys->i_clut_ver++ );
01996     bs_write( s, 4, 0 ); /* Reserved */
01997 
01998     for( i = 0; i < p_pal->i_entries; i++ )
01999     {
02000         bs_write( s, 8, i ); /* Clut entry id */
02001         bs_write( s, 1, p_pal->i_entries == 4 );   /* 2bit/entry flag */
02002         bs_write( s, 1, p_pal->i_entries == 16 );  /* 4bit/entry flag */
02003         bs_write( s, 1, p_pal->i_entries == 256 ); /* 8bit/entry flag */
02004         bs_write( s, 4, 0 ); /* Reserved */
02005         bs_write( s, 1, 1 ); /* Full range flag */
02006         bs_write( s, 8, p_pal->palette[i][3] ?  /* Y value */
02007                   (p_pal->palette[i][0] ? p_pal->palette[i][0] : 16) : 0 );
02008         bs_write( s, 8, p_pal->palette[i][1] ); /* Cr value */
02009         bs_write( s, 8, p_pal->palette[i][2] ); /* Cb value */
02010         bs_write( s, 8, 0xff - p_pal->palette[i][3] ); /* T value */
02011     }
02012 }
02013 
02014 static void encode_region_composition( encoder_t *p_enc, bs_t *s,
02015                                        subpicture_t *p_subpic )
02016 {
02017     encoder_sys_t *p_sys = p_enc->p_sys;
02018     subpicture_region_t *p_region;
02019     int i_region;
02020 
02021     for( i_region = 0, p_region = p_subpic->p_region; p_region;
02022          p_region = p_region->p_next, i_region++ )
02023     {
02024         int i_entries = 4, i_depth = 0x1, i_bg = 0;
02025         vlc_bool_t b_text =
02026             p_region->fmt.i_chroma == VLC_FOURCC('T','E','X','T');
02027 
02028         if( !b_text )
02029         {
02030             video_palette_t *p_pal = p_region->fmt.p_palette;
02031 
02032             if( !p_pal )
02033             {
02034                 msg_Err( p_enc, "subpicture has no palette - ignoring it" );
02035                 break;
02036             }
02037 
02038             i_entries = p_pal->i_entries;
02039             i_depth = i_entries == 4 ? 0x1 : i_entries == 16 ? 0x2 : 0x3;
02040 
02041             for( i_bg = 0; i_bg < p_pal->i_entries; i_bg++ )
02042             {
02043                 if( !p_pal->palette[i_bg][3] ) break;
02044             }
02045         }
02046 
02047         bs_write( s, 8, 0x0f ); /* Sync byte */
02048         bs_write( s, 8, DVBSUB_ST_REGION_COMPOSITION ); /* Segment type */
02049         bs_write( s, 16, 1 );   /* Page id */
02050 
02051         bs_write( s, 16, 10 + 6 + (b_text ? 2 : 0) ); /* Segment length */
02052         bs_write( s, 8, i_region );
02053         bs_write( s, 4, p_sys->i_region_ver++ );
02054 
02055         /* Region attributes */
02056         bs_write( s, 1, i_bg < i_entries ); /* Fill */
02057         bs_write( s, 3, 0 ); /* Reserved */
02058         bs_write( s, 16, p_sys->p_regions[i_region].i_width );
02059         bs_write( s, 16, p_sys->p_regions[i_region].i_height );
02060         bs_write( s, 3, i_depth );  /* Region level of compatibility */
02061         bs_write( s, 3, i_depth  ); /* Region depth */
02062         bs_write( s, 2, 0 ); /* Reserved */
02063         bs_write( s, 8, 1 ); /* Clut id */
02064         bs_write( s, 8, i_bg ); /* region 8bit pixel code */
02065         bs_write( s, 4, i_bg ); /* region 4bit pixel code */
02066         bs_write( s, 2, i_bg ); /* region 2bit pixel code */
02067         bs_write( s, 2, 0 ); /* Reserved */
02068 
02069         /* In our implementation we only have 1 object per region */
02070         bs_write( s, 16, i_region );
02071         bs_write( s, 2, b_text ? DVBSUB_OT_BASIC_CHAR:DVBSUB_OT_BASIC_BITMAP );
02072         bs_write( s, 2, 0 ); /* object provider flag */
02073         bs_write( s, 12, 0 );/* object horizontal position */
02074         bs_write( s, 4, 0 ); /* Reserved */
02075         bs_write( s, 12, 0 );/* object vertical position */
02076 
02077         if( b_text )
02078         {
02079             bs_write( s, 8, 1 ); /* foreground pixel code */
02080             bs_write( s, 8, 0 ); /* background pixel code */
02081         }
02082     }
02083 }
02084 
02085 static void encode_pixel_data( encoder_t *p_enc, bs_t *s,
02086                                subpicture_region_t *p_region,
02087                                vlc_bool_t b_top );
02088 
02089 static void encode_object( encoder_t *p_enc, bs_t *s, subpicture_t *p_subpic )
02090 {
02091     encoder_sys_t *p_sys = p_enc->p_sys;
02092     subpicture_region_t *p_region;
02093     int i_region;
02094 
02095     int i_length_pos, i_update_pos, i_pixel_data_pos;
02096 
02097     for( i_region = 0, p_region = p_subpic->p_region; p_region;
02098          p_region = p_region->p_next, i_region++ )
02099     {
02100         bs_write( s, 8, 0x0f ); /* Sync byte */
02101         bs_write( s, 8, DVBSUB_ST_OBJECT_DATA ); /* Segment type */
02102         bs_write( s, 16, 1 ); /* Page id */
02103 
02104         i_length_pos = bs_pos( s );
02105         bs_write( s, 16, 0 ); /* Segment length */
02106         bs_write( s, 16, i_region ); /* Object id */
02107         bs_write( s, 4, p_sys->i_region_ver++ );
02108 
02109         /* object coding method */
02110         switch( p_region->fmt.i_chroma )
02111         {
02112         case VLC_FOURCC( 'Y','U','V','P' ):
02113             bs_write( s, 2, 0 );
02114             break;
02115         case VLC_FOURCC( 'T','E','X','T' ):
02116             bs_write( s, 2, 1 );
02117             break;
02118         default:
02119             msg_Err( p_enc, "FOURCC %d not supported by encoder.", p_region->fmt.i_chroma );
02120             continue;
02121         }
02122 
02123         bs_write( s, 1, 0 ); /* non modifying color flag */
02124         bs_write( s, 1, 0 ); /* Reserved */
02125 
02126         if( p_region->fmt.i_chroma == VLC_FOURCC( 'T','E','X','T' ) )
02127         {
02128             int i_size, i;
02129 
02130             if( !p_region->psz_text ) continue;
02131 
02132             i_size = __MIN( strlen( p_region->psz_text ), 256 );
02133 
02134             bs_write( s, 8, i_size ); /* number of characters in string */
02135             for( i = 0; i < i_size; i++ )
02136             {
02137                 bs_write( s, 16, p_region->psz_text[i] );
02138             }
02139 
02140             /* Update segment length */
02141             SetWBE( &s->p_start[i_length_pos/8],
02142                     (bs_pos(s) - i_length_pos)/8 -2 );
02143             continue;
02144         }
02145 
02146         /* Coding of a bitmap object */
02147         i_update_pos = bs_pos( s );
02148         bs_write( s, 16, 0 ); /* topfield data block length */
02149         bs_write( s, 16, 0 ); /* bottomfield data block length */
02150 
02151         /* Top field */
02152         i_pixel_data_pos = bs_pos( s );
02153         encode_pixel_data( p_enc, s, p_region, VLC_TRUE );
02154         i_pixel_data_pos = ( bs_pos( s ) - i_pixel_data_pos ) / 8;
02155         SetWBE( &s->p_start[i_update_pos/8], i_pixel_data_pos );
02156 
02157         /* Bottom field */
02158         i_pixel_data_pos = bs_pos( s );
02159         encode_pixel_data( p_enc, s, p_region, VLC_FALSE );
02160         i_pixel_data_pos = ( bs_pos( s ) - i_pixel_data_pos ) / 8;
02161         SetWBE( &s->p_start[i_update_pos/8+2], i_pixel_data_pos );
02162 
02163         /* Stuffing for word alignment */
02164         bs_align_0( s );
02165         if( bs_pos( s ) % 16 ) bs_write( s, 8, 0 );
02166 
02167         /* Update segment length */
02168         SetWBE( &s->p_start[i_length_pos/8], (bs_pos(s) - i_length_pos)/8 -2 );
02169     }
02170 }
02171 
02172 static void encode_pixel_line_2bp( encoder_t *p_enc, bs_t *s,
02173                                    subpicture_region_t *p_region,
02174                                    int i_line );
02175 static void encode_pixel_line_4bp( encoder_t *p_enc, bs_t *s,
02176                                    subpicture_region_t *p_region,
02177                                    int i_line );
02178 static void encode_pixel_line_8bp( encoder_t *p_enc, bs_t *s,
02179                                    subpicture_region_t *p_region,
02180                                    int i_line );
02181 static void encode_pixel_data( encoder_t *p_enc, bs_t *s,
02182                                subpicture_region_t *p_region,
02183                                vlc_bool_t b_top )
02184 {
02185     unsigned int i_line;
02186 
02187     /* Sanity check */
02188     if( p_region->fmt.i_chroma != VLC_FOURCC('Y','U','V','P') ) return;
02189 
02190     /* Encode line by line */
02191     for( i_line = !b_top; i_line < p_region->fmt.i_visible_height;
02192          i_line += 2 )
02193     {
02194         switch( p_region->fmt.p_palette->i_entries )
02195         {
02196         case 0:
02197             break;
02198 
02199         case 4:
02200             bs_write( s, 8, 0x10 ); /* 2 bit/pixel code string */
02201             encode_pixel_line_2bp( p_enc, s, p_region, i_line );
02202             break;
02203 
02204         case 16:
02205             bs_write( s, 8, 0x11 ); /* 4 bit/pixel code string */
02206             encode_pixel_line_4bp( p_enc, s, p_region, i_line );
02207             break;
02208 
02209         case 256:
02210             bs_write( s, 8, 0x12 ); /* 8 bit/pixel code string */
02211             encode_pixel_line_8bp( p_enc, s, p_region, i_line );
02212             break;
02213 
02214         default:
02215             msg_Err( p_enc, "subpicture palette (%i) not handled",
02216                      p_region->fmt.p_palette->i_entries );
02217             break;
02218         }
02219 
02220         bs_write( s, 8, 0xf0 ); /* End of object line code */
02221     }
02222 }
02223 
02224 static void encode_pixel_line_2bp( encoder_t *p_enc, bs_t *s,
02225                                    subpicture_region_t *p_region,
02226                                    int i_line )
02227 {
02228     unsigned int i, i_length = 0;
02229     int i_pitch = p_region->picture.p->i_pitch;
02230     uint8_t *p_data = &p_region->picture.p->p_pixels[ i_pitch * i_line ];
02231     int i_last_pixel = p_data[0];
02232 
02233     for( i = 0; i <= p_region->fmt.i_visible_width; i++ )
02234     {
02235         if( i != p_region->fmt.i_visible_width &&
02236             p_data[i] == i_last_pixel && i_length != 284 )
02237         {
02238             i_length++;
02239             continue;
02240         }
02241 
02242         if( i_length == 1 || i_length == 11 || i_length == 28 )
02243         {
02244             /* 2bit/pixel code */
02245             if( i_last_pixel ) bs_write( s, 2, i_last_pixel );
02246             else
02247             {
02248                 bs_write( s, 2, 0 );
02249                 bs_write( s, 1, 0 );
02250                 bs_write( s, 1, 1 ); /* pseudo color 0 */
02251             }
02252             i_length--;
02253         }
02254 
02255         if( i_length == 2 )
02256         {
02257             if( i_last_pixel )
02258             {
02259                 bs_write( s, 2, i_last_pixel );
02260                 bs_write( s, 2, i_last_pixel );
02261             }
02262             else
02263             {
02264                 bs_write( s, 2, 0 );
02265                 bs_write( s, 1, 0 );
02266                 bs_write( s, 1, 0 );
02267                 bs_write( s, 2, 1 ); /* 2 * pseudo color 0 */
02268             }
02269         }
02270         else if( i_length > 2 )
02271         {
02272             bs_write( s, 2, 0 );
02273             if( i_length <= 10 )
02274             {
02275                 bs_write( s, 1, 1 );
02276                 bs_write( s, 3, i_length - 3 );
02277                 bs_write( s, 2, i_last_pixel );
02278             }
02279             else
02280             {
02281                 bs_write( s, 1, 0 );
02282                 bs_write( s, 1, 0 );
02283 
02284                 if( i_length <= 27 )
02285                 {
02286                     bs_write( s, 2, 2 );
02287                     bs_write( s, 4, i_length - 12 );
02288                     bs_write( s, 2, i_last_pixel );
02289                 }
02290                 else
02291                 {
02292                     bs_write( s, 2, 3 );
02293                     bs_write( s, 8, i_length - 29 );
02294                     bs_write( s, 2, i_last_pixel );
02295                 }
02296             }
02297         }
02298 
02299         if( i == p_region->fmt.i_visible_width ) break;
02300 
02301         i_last_pixel = p_data[i];
02302         i_length = 1;
02303     }
02304 
02305     /* Stop */
02306     bs_write( s, 2, 0 );
02307     bs_write( s, 1, 0 );
02308     bs_write( s, 1, 0 );
02309     bs_write( s, 2, 0 );
02310 
02311     /* Stuffing */
02312     bs_align_0( s );
02313 }
02314 
02315 static void encode_pixel_line_4bp( encoder_t *p_enc, bs_t *s,
02316                                    subpicture_region_t *p_region,
02317                                    int i_line )
02318 {
02319     unsigned int i, i_length = 0;
02320     int i_pitch = p_region->picture.p->i_pitch;
02321     uint8_t *p_data = &p_region->picture.p->p_pixels[ i_pitch * i_line ];
02322     int i_last_pixel = p_data[0];
02323 
02324     for( i = 0; i <= p_region->fmt.i_visible_width; i++ )
02325     {
02326         if( i != p_region->fmt.i_visible_width &&
02327             p_data[i] == i_last_pixel && i_length != 280 )
02328         {
02329             i_length++;
02330             continue;
02331         }
02332 
02333         if( i_length == 1 || (i_length == 3 && i_last_pixel) || i_length == 8 )
02334         {
02335             /* 4bit/pixel code */
02336             if( i_last_pixel ) bs_write( s, 4, i_last_pixel );
02337             else
02338             {
02339                 bs_write( s, 4, 0 );
02340                 bs_write( s, 1, 1 );
02341                 bs_write( s, 1, 1 );
02342                 bs_write( s, 2, 0 ); /* pseudo color 0 */
02343             }
02344             i_length--;
02345         }
02346 
02347         if( i_length == 2 )
02348         {
02349             if( i_last_pixel )
02350             {
02351                 bs_write( s, 4, i_last_pixel );
02352                 bs_write( s, 4, i_last_pixel );
02353             }
02354             else
02355             {
02356                 bs_write( s, 4, 0 );
02357                 bs_write( s, 1, 1 );
02358                 bs_write( s, 1, 1 );
02359                 bs_write( s, 2, 1 ); /* 2 * pseudo color 0 */
02360             }
02361         }
02362         else if( !i_last_pixel && i_length >= 3 && i_length <= 9 )
02363         {
02364             bs_write( s, 4, 0 );
02365             bs_write( s, 1, 0 );
02366             bs_write( s, 3, i_length - 2 ); /* (i_length - 2) * color 0 */
02367         }
02368         else if( i_length > 2 )
02369         {
02370             bs_write( s, 4, 0 );
02371             bs_write( s, 1, 1 );
02372 
02373             if( i_length <= 7 )
02374             {
02375                 bs_write( s, 1, 0 );
02376                 bs_write( s, 2, i_length - 4 );
02377                 bs_write( s, 4, i_last_pixel );
02378             }
02379             else
02380             {
02381                 bs_write( s, 1, 1 );
02382 
02383                 if( i_length <= 24 )
02384                 {
02385                     bs_write( s, 2, 2 );
02386                     bs_write( s, 4, i_length - 9 );
02387                     bs_write( s, 4, i_last_pixel );
02388                 }
02389                 else
02390                 {
02391                     bs_write( s, 2, 3 );
02392                     bs_write( s, 8, i_length - 25 );
02393                     bs_write( s, 4, i_last_pixel );
02394                 }
02395             }
02396         }
02397 
02398         if( i == p_region->fmt.i_visible_width ) break;
02399 
02400         i_last_pixel = p_data[i];
02401         i_length = 1;
02402     }
02403 
02404     /* Stop */
02405     bs_write( s, 8, 0 );
02406 
02407     /* Stuffing */
02408     bs_align_0( s );
02409 }
02410 
02411 static void encode_pixel_line_8bp( encoder_t *p_enc, bs_t *s,
02412                                    subpicture_region_t *p_region,
02413                                    int i_line )
02414 {
02415     unsigned int i, i_length = 0;
02416     int i_pitch = p_region->picture.p->i_pitch;
02417     uint8_t *p_data = &p_region->picture.p->p_pixels[ i_pitch * i_line ];
02418     int i_last_pixel = p_data[0];
02419 
02420     for( i = 0; i <= p_region->fmt.i_visible_width; i++ )
02421     {
02422         if( i != p_region->fmt.i_visible_width &&
02423             p_data[i] == i_last_pixel && i_length != 127 )
02424         {
02425             i_length++;
02426             continue;
02427         }
02428 
02429         if( i_length == 1 && i_last_pixel )
02430         {
02431             /* 8bit/pixel code */
02432             bs_write( s, 8, i_last_pixel );
02433         }
02434         else if( i_length == 2 && i_last_pixel )
02435         {
02436             /* 8bit/pixel code */
02437             bs_write( s, 8, i_last_pixel );
02438             bs_write( s, 8, i_last_pixel );
02439         }
02440         else if( i_length <= 127 )
02441         {
02442             bs_write( s, 8, 0 );
02443 
02444             if( !i_last_pixel )
02445             {
02446                 bs_write( s, 1, 0 );
02447                 bs_write( s, 7, i_length ); /* pseudo color 0 */
02448             }
02449             else
02450             {
02451                 bs_write( s, 1, 1 );
02452                 bs_write( s, 7, i_length );
02453                 bs_write( s, 8, i_last_pixel );
02454             }
02455         }
02456 
02457         if( i == p_region->fmt.i_visible_width ) break;
02458 
02459         i_last_pixel = p_data[i];
02460         i_length = 1;
02461     }
02462 
02463     /* Stop */
02464     bs_write( s, 8, 0 );
02465     bs_write( s, 8, 0 );
02466 
02467     /* Stuffing */
02468     bs_align_0( s );
02469 }

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