* DVB subtitles encoder (developed for Anevia, www.anevia.com)
*****************************************************************************
* Copyright (C) 2003 ANEVIA
- * Copyright (C) 2003-2004 VideoLAN
+ * Copyright (C) 2003-2005 VideoLAN
* $Id$
*
* Authors: Gildas Bazin <gbazin@videolan.org>
*****************************************************************************/
/*****************************************************************************
* Preamble
+ *
+ * FIXME:
+ * DVB subtitles coded as strings of characters are not handled correctly.
+ * The character codes in the string should actually be indexes refering to a
+ * character table identified in the subtitle descriptor.
*****************************************************************************/
#include <vlc/vlc.h>
#include <vlc/vout.h>
vlc_module_begin();
set_description( _("DVB subtitles decoder") );
set_capability( "decoder", 50 );
+ set_category( CAT_INPUT );
+ set_subcategory( SUBCAT_INPUT_SCODEC );
set_callbacks( Open, Close );
# define ENC_CFG_PREFIX "sout-dvbsub-"
int i_y;
int i_fg_pc;
int i_bg_pc;
+ char *psz_text; /* for string of characters objects */
} dvbsub_objectdef_t;
int i_ancillary_id;
mtime_t i_pts;
+ vlc_bool_t b_page;
dvbsub_page_t *p_page;
dvbsub_region_t *p_regions;
dvbsub_clut_t *p_cluts;
p_sys->i_pts = 0;
p_sys->i_id = p_dec->fmt_in.subs.dvb.i_id & 0xFFFF;
p_sys->i_ancillary_id = p_dec->fmt_in.subs.dvb.i_id >> 16;
+
p_sys->p_regions = NULL;
p_sys->p_cluts = NULL;
p_sys->p_page = NULL;
msg_Dbg( p_dec, "subtitle packet received: "I64Fd, p_sys->i_pts );
#endif
+ p_sys->b_page = VLC_FALSE;
while( bs_show( &p_sys->bs, 8 ) == 0x0f ) /* Sync byte */
{
decode_segment( p_dec, &p_sys->bs );
}
/* Check if the page is to be displayed */
- if( p_sys->p_page ) p_spu = render( p_dec );
+ if( p_sys->p_page && p_sys->b_page ) p_spu = render( p_dec );
block_Release( p_block );
return;
}
+ if( p_sys->i_ancillary_id != p_sys->i_id &&
+ i_type == DVBSUB_ST_PAGE_COMPOSITION &&
+ i_page_id == p_sys->i_ancillary_id )
+ {
+#ifdef DEBUG_DVBSUB
+ msg_Dbg( p_dec, "skipped invalid ancillary subtitle packet" );
+#endif
+ bs_skip( s, 8 * ( 2 + i_size ) );
+ return;
+ }
+
#ifdef DEBUG_DVBSUB
if( i_page_id == p_sys->i_id )
msg_Dbg( p_dec, "segment (id: %i)", i_page_id );
decoder_sys_t *p_sys = p_dec->p_sys;
uint16_t i_segment_length;
uint16_t i_processed_length;
- dvbsub_clut_t *p_clut;
+ dvbsub_clut_t *p_clut, *p_next;
int i_id, i_version;
i_segment_length = bs_read( s, 16 );
p_sys->p_cluts = p_clut;
}
- /* TODO: initialize to default clut */
+ /* Initialize to default clut */
+ p_next = p_clut->p_next;
+ *p_clut = p_sys->default_clut;
+ p_clut->p_next = p_next;
/* We don't have this version of the CLUT: Parse it */
p_clut->i_version = i_version;
* not have more than 1 bit set to one, but some streams don't
* respect this note. */
- if( i_type & 0x04)
+ if( i_type & 0x04 && i_id < 4 )
{
p_clut->c_2b[i_id].Y = y;
p_clut->c_2b[i_id].Cr = cr;
p_clut->c_2b[i_id].Cb = cb;
p_clut->c_2b[i_id].T = t;
}
- if( i_type & 0x02)
+ if( i_type & 0x02 && i_id < 16 )
{
p_clut->c_4b[i_id].Y = y;
p_clut->c_4b[i_id].Cr = cr;
p_clut->c_4b[i_id].Cb = cb;
p_clut->c_4b[i_id].T = t;
}
- if( i_type & 0x01)
+ if( i_type & 0x01 )
{
p_clut->c_8b[i_id].Y = y;
p_clut->c_8b[i_id].Cr = cr;
#endif
free_all( p_dec );
}
- else if( !p_sys->p_page && i_state != DVBSUB_PCS_STATE_ACQUISITION )
+ else if( !p_sys->p_page && i_state != DVBSUB_PCS_STATE_ACQUISITION &&
+ i_state != DVBSUB_PCS_STATE_CHANGE )
{
-#ifdef DEBUG_DVBSUB
/* Not a full PCS, we need to wait for one */
msg_Dbg( p_dec, "didn't receive an acquisition page yet" );
+
+#if 0 /* Try to start decoding even without an acquisition page */
bs_skip( s, 8 * (i_segment_length - 2) );
return;
#endif
p_sys->p_page->i_version = i_version;
p_sys->p_page->i_timeout = i_timeout;
+ p_sys->b_page = VLC_TRUE;
/* Number of regions */
p_sys->p_page->i_region_defs = (i_segment_length - 2) / 6;
i_4_bg = bs_read( s, 4 );
i_2_bg = bs_read( s, 2 );
bs_skip( s, 2 ); /* Reserved */
- p_region->i_object_defs = 0;
+
+ /* Free old object defs */
+ while( p_region->i_object_defs )
+ {
+ int i = p_region->i_object_defs - 1;
+ if( p_region->p_object_defs[i].psz_text )
+ free( p_region->p_object_defs[i].psz_text );
+ if( !i ) free( p_region->p_object_defs );
+
+ p_region->i_object_defs--;
+ }
+ p_region->p_object_defs = NULL;
/* Extra sanity checks */
if( p_region->i_width != i_width || p_region->i_height != i_height )
}
p_region->p_pixbuf = malloc( i_height * i_width );
+ p_region->i_depth = 0;
b_fill = VLC_TRUE;
}
- if( p_region->i_depth != i_depth ||
- p_region->i_level_comp != i_level_comp || p_region->i_clut != i_clut )
+ if( p_region->i_depth && (p_region->i_depth != i_depth ||
+ p_region->i_level_comp != i_level_comp || p_region->i_clut != i_clut) )
{
msg_Dbg( p_dec, "region parameters changed (not allowed)" );
}
p_obj->i_x = bs_read( s, 12 );
bs_skip( s, 4 ); /* Reserved */
p_obj->i_y = bs_read( s, 12 );
+ p_obj->psz_text = 0;
i_processed_length += 6;
i_version = bs_read( s, 4 );
i_coding_method = bs_read( s, 2 );
- if( i_coding_method )
+ if( i_coding_method > 1 )
{
- /* TODO: DVB subtitling as characters */
- msg_Dbg( p_dec, "DVB subtitling as characters is not handled!" );
+ msg_Dbg( p_dec, "DVB subtitling method is not handled!" );
bs_skip( s, 8 * (i_segment_length - 2) - 6 );
return;
}
/* Sanity check */
if( i_segment_length < i_topfield + i_bottomfield + 7 ||
- s->p_start + i_topfield + i_bottomfield > s->p_end )
+ p_topfield + i_topfield + i_bottomfield > s->p_end )
{
msg_Dbg( p_dec, "corrupted object data" );
return;
}
else
{
- /* TODO: DVB subtitling as characters */
+ /* DVB subtitling as characters */
+ int i_number_of_codes = bs_read( s, 8 );
+ uint8_t* p_start = s->p_start + bs_pos( s ) / 8;
+
+ /* Sanity check */
+ if( i_segment_length < i_number_of_codes*2 + 4 ||
+ p_start + i_number_of_codes*2 > s->p_end )
+ {
+ msg_Dbg( p_dec, "corrupted object data" );
+ return;
+ }
+
+ for( p_region = p_sys->p_regions; p_region != NULL;
+ p_region = p_region->p_next )
+ {
+ for( i = 0; i < p_region->i_object_defs; i++ )
+ {
+ int j;
+
+ if( p_region->p_object_defs[i].i_id != i_id ) continue;
+
+ p_region->p_object_defs[i].psz_text =
+ realloc( p_region->p_object_defs[i].psz_text,
+ i_number_of_codes + 1 );
+
+ for( j = 0; j < i_number_of_codes; j++ )
+ {
+ p_region->p_object_defs[i].psz_text[j] = bs_read( s, 16 );
+ }
+ p_region->p_object_defs[i].psz_text[j] = 0;
+ }
+ }
}
#ifdef DEBUG_DVBSUB
else
{
/* 1 pixel color 0 */
- i_count = 0;
+ i_count = 1;
}
}
}
for( p_reg = p_sys->p_regions; p_reg != NULL; p_reg = p_reg_next )
{
+ int i;
+
p_reg_next = p_reg->p_next;
+ for( i = 0; i < p_reg->i_object_defs; i++ )
+ if( p_reg->p_object_defs[i].psz_text )
+ free( p_reg->p_object_defs[i].psz_text );
if( p_reg->i_object_defs ) free( p_reg->p_object_defs );
if( p_reg->p_pixbuf ) free( p_reg->p_pixbuf );
free( p_reg );
if( !p_region )
{
- msg_Err( p_dec, "no region founddddd!!!" );
+ msg_Dbg( p_dec, "region %i not found", p_regiondef->i_id );
continue;
}
}
if( !p_clut )
{
- msg_Warn( p_dec, "clut %i not found", p_region->i_clut );
- p_clut = &p_sys->default_clut;
+ msg_Dbg( p_dec, "clut %i not found", p_region->i_clut );
+ continue;
}
/* Create new SPU region */
memset( &fmt, 0, sizeof(video_format_t) );
fmt.i_chroma = VLC_FOURCC('Y','U','V','P');
- fmt.i_aspect = VOUT_ASPECT_FACTOR;
+ fmt.i_aspect = 0; /* 0 means use aspect ratio of background video */
fmt.i_width = fmt.i_visible_width = p_region->i_width;
fmt.i_height = fmt.i_visible_height = p_region->i_height;
fmt.i_x_offset = fmt.i_y_offset = 0;
p_src += p_region->i_width;
p_dst += i_pitch;
}
+
+ /* Check subtitles encoded as strings of characters
+ * (since there are not rendered in the pixbuffer) */
+ for( j = 0; j < p_region->i_object_defs; j++ )
+ {
+ dvbsub_objectdef_t *p_object_def = &p_region->p_object_defs[i];
+
+ if( p_object_def->i_type != 1 || !p_object_def->psz_text )
+ continue;
+
+ /* Create new SPU region */
+ memset( &fmt, 0, sizeof(video_format_t) );
+ fmt.i_chroma = VLC_FOURCC('T','E','X','T');
+ fmt.i_aspect = VOUT_ASPECT_FACTOR;
+ fmt.i_width = fmt.i_visible_width = p_region->i_width;
+ fmt.i_height = fmt.i_visible_height = p_region->i_height;
+ fmt.i_x_offset = fmt.i_y_offset = 0;
+ p_spu_region = p_spu->pf_create_region( VLC_OBJECT(p_dec), &fmt );
+ if( !p_region )
+ {
+ msg_Err( p_dec, "cannot allocate SPU region" );
+ continue;
+ }
+
+ p_spu_region->psz_text = strdup( p_object_def->psz_text );
+ p_spu_region->i_x = p_regiondef->i_x + p_object_def->i_x;
+ p_spu_region->i_y = p_regiondef->i_y + p_object_def->i_y;
+ *pp_spu_region = p_spu_region;
+ pp_spu_region = &p_spu_region->p_next;
+ }
}
/* Set the pf_render callback */
/*****************************************************************************
* encoder_sys_t : encoder descriptor
*****************************************************************************/
+typedef struct encoder_region_t
+{
+ int i_width;
+ int i_height;
+
+} encoder_region_t;
+
struct encoder_sys_t
{
unsigned int i_page_ver;
unsigned int i_region_ver;
unsigned int i_clut_ver;
- /*
- * Input properties
- */
- /*
- * Common properties
- */
+ int i_regions;
+ encoder_region_t *p_regions;
+
mtime_t i_pts;
};
p_sys->i_page_ver = 0;
p_sys->i_region_ver = 0;
p_sys->i_clut_ver = 0;
+ p_sys->i_regions = 0;
+ p_sys->p_regions = 0;
return VLC_SUCCESS;
}
bs_write( s, 8, 0xff ); /* End marker */
p_block->i_buffer = bs_pos( s ) / 8;
p_block->i_pts = p_block->i_dts = p_subpic->i_start;
- if( !p_subpic->b_ephemer && p_subpic->i_stop )
+ if( !p_subpic->b_ephemer && p_subpic->i_stop > p_subpic->i_start )
+ {
+ block_t *p_block_stop;
+
p_block->i_length = p_subpic->i_stop - p_subpic->i_start;
+ /* Send another (empty) subtitle to signal the end of display */
+ p_block_stop = block_New( p_enc, 64000 );
+ bs_init( s, p_block_stop->p_buffer, p_block_stop->i_buffer );
+ bs_write( s, 8, 0x20 ); /* Data identifier */
+ bs_write( s, 8, 0x0 ); /* Subtitle stream id */
+ encode_page_composition( p_enc, s, 0 );
+ bs_write( s, 8, 0x0f ); /* Sync byte */
+ bs_write( s, 8, DVBSUB_ST_ENDOFDISPLAY ); /* Segment type */
+ bs_write( s, 16, 1 ); /* Page id */
+ bs_write( s, 16, 0 ); /* Segment length */
+ bs_write( s, 8, 0xff ); /* End marker */
+ p_block_stop->i_buffer = bs_pos( s ) / 8;
+ p_block_stop->i_pts = p_block_stop->i_dts = p_subpic->i_stop;
+ block_ChainAppend( &p_block, p_block_stop );
+ p_block_stop->i_length = 100000;//p_subpic->i_stop - p_subpic->i_start;
+ }
+
msg_Dbg( p_enc, "subpicture encoded properly" );
return p_block;
encoder_t *p_enc = (encoder_t *)p_this;
encoder_sys_t *p_sys = p_enc->p_sys;
+ if( p_sys->i_regions ) free( p_sys->p_regions );
free( p_sys );
}
{
encoder_sys_t *p_sys = p_enc->p_sys;
subpicture_region_t *p_region;
- int i_regions;
+ vlc_bool_t b_mode_change = VLC_FALSE;
+ int i_regions, i_timeout;
bs_write( s, 8, 0x0f ); /* Sync byte */
bs_write( s, 8, DVBSUB_ST_PAGE_COMPOSITION ); /* Segment type */
bs_write( s, 16, 1 ); /* Page id */
- for( i_regions = 0, p_region = p_subpic->p_region; p_region;
- p_region = p_region->p_next, i_regions++ );
+ for( i_regions = 0, p_region = p_subpic ? p_subpic->p_region : 0;
+ p_region; p_region = p_region->p_next, i_regions++ )
+ {
+ if( i_regions >= p_sys->i_regions )
+ {
+ encoder_region_t region;
+ region.i_width = region.i_height = 0;
+ p_sys->p_regions =
+ realloc( p_sys->p_regions, sizeof(encoder_region_t) *
+ (p_sys->i_regions + 1) );
+ p_sys->p_regions[p_sys->i_regions++] = region;
+ }
+
+ if( p_sys->p_regions[i_regions].i_width <
+ (int)p_region->fmt.i_visible_width )
+ {
+ b_mode_change = VLC_TRUE;
+ msg_Dbg( p_enc, "region %i width change: %i -> %i",
+ i_regions, p_sys->p_regions[i_regions].i_width,
+ p_region->fmt.i_visible_width );
+ p_sys->p_regions[i_regions].i_width =
+ p_region->fmt.i_visible_width;
+ }
+ if( p_sys->p_regions[i_regions].i_height <
+ (int)p_region->fmt.i_visible_height )
+ {
+ b_mode_change = VLC_TRUE;
+ msg_Dbg( p_enc, "region %i height change: %i -> %i",
+ i_regions, p_sys->p_regions[i_regions].i_height,
+ p_region->fmt.i_visible_height );
+ p_sys->p_regions[i_regions].i_height =
+ p_region->fmt.i_visible_height;
+ }
+ }
bs_write( s, 16, i_regions * 6 + 2 ); /* Segment length */
- bs_write( s, 8, 5 ); /* Timeout */
+ i_timeout = 0;
+ if( p_subpic && !p_subpic->b_ephemer &&
+ p_subpic->i_stop > p_subpic->i_start )
+ {
+ i_timeout = (p_subpic->i_stop - p_subpic->i_start) / 1000000;
+ }
+
+ bs_write( s, 8, i_timeout + 15 ); /* Timeout */
bs_write( s, 4, p_sys->i_page_ver++ );
- bs_write( s, 2, DVBSUB_PCS_STATE_ACQUISITION );
+ bs_write( s, 2, b_mode_change ?
+ DVBSUB_PCS_STATE_CHANGE : DVBSUB_PCS_STATE_ACQUISITION );
bs_write( s, 2, 0 ); /* Reserved */
- for( i_regions = 0, p_region = p_subpic->p_region; p_region;
- p_region = p_region->p_next, i_regions++ )
+ for( i_regions = 0, p_region = p_subpic ? p_subpic->p_region : 0;
+ p_region; p_region = p_region->p_next, i_regions++ )
{
bs_write( s, 8, i_regions );
bs_write( s, 8, 0 ); /* Reserved */
{
encoder_sys_t *p_sys = p_enc->p_sys;
subpicture_region_t *p_region = p_subpic->p_region;
- video_palette_t *p_pal;
+ video_palette_t *p_pal, pal;
int i;
/* Sanity check */
- if( !p_region || !p_region->fmt.p_palette ||
- p_region->fmt.i_chroma != VLC_FOURCC('Y','U','V','P') ) return;
+ if( !p_region ) return;
+
+ if( p_region->fmt.i_chroma == VLC_FOURCC('Y','U','V','P') )
+ {
+ p_pal = p_region->fmt.p_palette;
+ }
+ else
+ {
+ pal.i_entries = 4;
+ for( i = 0; i < 4; i++ )
+ {
+ pal.palette[i][0] = 0;
+ pal.palette[i][1] = 0;
+ pal.palette[i][2] = 0;
+ pal.palette[i][3] = 0;
+ }
+ p_pal = &pal;
+ }
bs_write( s, 8, 0x0f ); /* Sync byte */
bs_write( s, 8, DVBSUB_ST_CLUT_DEFINITION ); /* Segment type */
bs_write( s, 16, 1 ); /* Page id */
- p_pal = p_region->fmt.p_palette;
-
bs_write( s, 16, p_pal->i_entries * 6 + 2 ); /* Segment length */
bs_write( s, 8, 1 ); /* Clut id */
bs_write( s, 4, p_sys->i_clut_ver++ );
bs_write( s, 1, p_pal->i_entries == 256 ); /* 8bit/entry flag */
bs_write( s, 4, 0 ); /* Reserved */
bs_write( s, 1, 1 ); /* Full range flag */
- bs_write( s, 8, p_pal->palette[i][0] ); /* Y value */
+ bs_write( s, 8, p_pal->palette[i][3] ? /* Y value */
+ (p_pal->palette[i][0] ? p_pal->palette[i][0] : 16) : 0 );
bs_write( s, 8, p_pal->palette[i][1] ); /* Cr value */
bs_write( s, 8, p_pal->palette[i][2] ); /* Cb value */
bs_write( s, 8, 0xff - p_pal->palette[i][3] ); /* T value */
{
encoder_sys_t *p_sys = p_enc->p_sys;
subpicture_region_t *p_region;
- int i_regions;
+ int i_region;
- for( i_regions = 0, p_region = p_subpic->p_region; p_region;
- p_region = p_region->p_next, i_regions++ )
+ for( i_region = 0, p_region = p_subpic->p_region; p_region;
+ p_region = p_region->p_next, i_region++ )
{
- video_palette_t *p_pal = p_region->fmt.p_palette;
- int i_depth = p_pal->i_entries == 4 ? 0x1 :
- p_pal->i_entries == 16 ? 0x2 : 0x3;
+ int i_entries = 4, i_depth = 0x1, i_bg = 0;
+ vlc_bool_t b_text =
+ p_region->fmt.i_chroma == VLC_FOURCC('T','E','X','T');
+
+ if( !b_text )
+ {
+ video_palette_t *p_pal = p_region->fmt.p_palette;
+
+ i_entries = p_pal->i_entries;
+ i_depth = i_entries == 4 ? 0x1 : i_entries == 16 ? 0x2 : 0x3;
+
+ for( i_bg = 0; i_bg < p_pal->i_entries; i_bg++ )
+ {
+ if( !p_pal->palette[i_bg][3] ) break;
+ }
+ }
bs_write( s, 8, 0x0f ); /* Sync byte */
bs_write( s, 8, DVBSUB_ST_REGION_COMPOSITION ); /* Segment type */
bs_write( s, 16, 1 ); /* Page id */
- bs_write( s, 16, 10 + 6 ); /* Segment length */
- bs_write( s, 8, i_regions );
+ bs_write( s, 16, 10 + 6 + (b_text ? 2 : 0) ); /* Segment length */
+ bs_write( s, 8, i_region );
bs_write( s, 4, p_sys->i_region_ver++ );
/* Region attributes */
- bs_write( s, 1, 0 ); /* Fill */
+ bs_write( s, 1, i_bg < i_entries ); /* Fill */
bs_write( s, 3, 0 ); /* Reserved */
- bs_write( s, 16, p_region->fmt.i_visible_width );
- bs_write( s, 16, p_region->fmt.i_visible_height );
+ bs_write( s, 16, p_sys->p_regions[i_region].i_width );
+ bs_write( s, 16, p_sys->p_regions[i_region].i_height );
bs_write( s, 3, i_depth ); /* Region level of compatibility */
bs_write( s, 3, i_depth ); /* Region depth */
bs_write( s, 2, 0 ); /* Reserved */
bs_write( s, 8, 1 ); /* Clut id */
- bs_write( s, 8, 0 ); /* region 8bit pixel code */
- bs_write( s, 4, 0 ); /* region 4bit pixel code */
- bs_write( s, 2, 0 ); /* region 2bit pixel code */
+ bs_write( s, 8, i_bg ); /* region 8bit pixel code */
+ bs_write( s, 4, i_bg ); /* region 4bit pixel code */
+ bs_write( s, 2, i_bg ); /* region 2bit pixel code */
bs_write( s, 2, 0 ); /* Reserved */
/* In our implementation we only have 1 object per region */
- bs_write( s, 16, i_regions );
- bs_write( s, 2, DVBSUB_OT_BASIC_BITMAP );
+ bs_write( s, 16, i_region );
+ bs_write( s, 2, b_text ? DVBSUB_OT_BASIC_CHAR:DVBSUB_OT_BASIC_BITMAP );
bs_write( s, 2, 0 ); /* object provider flag */
bs_write( s, 12, 0 ); /* object horizontal position */
bs_write( s, 4, 0 ); /* Reserved */
bs_write( s, 12, 0 ); /* object vertical position */
+
+ if( b_text )
+ {
+ bs_write( s, 8, 1 ); /* foreground pixel code */
+ bs_write( s, 8, 0 ); /* background pixel code */
+ }
}
}
static void encode_object( encoder_t *p_enc, bs_t *s, subpicture_t *p_subpic )
{
- encoder_sys_t *p_sys = p_enc->p_sys;
+ encoder_sys_t *p_sys = p_enc->p_sys;
subpicture_region_t *p_region;
- int i_regions;
+ int i_region;
int i_length_pos, i_update_pos, i_pixel_data_pos;
- for( i_regions = 0, p_region = p_subpic->p_region; p_region;
- p_region = p_region->p_next, i_regions++ )
+ for( i_region = 0, p_region = p_subpic->p_region; p_region;
+ p_region = p_region->p_next, i_region++ )
{
bs_write( s, 8, 0x0f ); /* Sync byte */
bs_write( s, 8, DVBSUB_ST_OBJECT_DATA ); /* Segment type */
i_length_pos = bs_pos( s );
bs_write( s, 16, 0 ); /* Segment length */
- bs_write( s, 16, i_regions ); /* Object id */
+ bs_write( s, 16, i_region ); /* Object id */
bs_write( s, 4, p_sys->i_region_ver++ );
- bs_write( s, 2, 0 ); /* object coding method */
+
+ /* object coding method */
+ switch( p_region->fmt.i_chroma )
+ {
+ case VLC_FOURCC( 'Y','U','V','P' ):
+ bs_write( s, 2, 0 );
+ break;
+ case VLC_FOURCC( 'T','E','X','T' ):
+ bs_write( s, 2, 1 );
+ break;
+ }
bs_write( s, 1, 0 ); /* non modifying color flag */
bs_write( s, 1, 0 ); /* Reserved */
+ if( p_region->fmt.i_chroma == VLC_FOURCC( 'T','E','X','T' ) )
+ {
+ int i_size, i;
+
+ if( !p_region->psz_text ) continue;
+
+ i_size = __MIN( strlen( p_region->psz_text ), 256 );
+
+ bs_write( s, 8, i_size ); /* number of characters in string */
+ for( i = 0; i < i_size; i++ )
+ {
+ bs_write( s, 16, p_region->psz_text[i] );
+ }
+
+ /* Update segment length */
+ SetWBE( &s->p_start[i_length_pos/8],
+ (bs_pos(s) - i_length_pos)/8 -2 );
+ continue;
+ }
+
+ /* Coding of a bitmap object */
+
i_update_pos = bs_pos( s );
bs_write( s, 16, 0 ); /* topfield data block length */
bs_write( s, 16, 0 ); /* bottomfield data block length */
static void encode_pixel_line_4bp( encoder_t *p_enc, bs_t *s,
subpicture_region_t *p_region,
int i_line );
+static void encode_pixel_line_8bp( encoder_t *p_enc, bs_t *s,
+ subpicture_region_t *p_region,
+ int i_line );
static void encode_pixel_data( encoder_t *p_enc, bs_t *s,
subpicture_region_t *p_region,
vlc_bool_t b_top )
encode_pixel_line_4bp( p_enc, s, p_region, i_line );
break;
+ case 256:
+ bs_write( s, 8, 0x12 ); /* 8 bit/pixel code string */
+ encode_pixel_line_8bp( p_enc, s, p_region, i_line );
+ break;
+
default:
msg_Err( p_enc, "subpicture palette (%i) not handled",
p_region->fmt.p_palette->i_entries );
for( i = 0; i <= p_region->fmt.i_visible_width; i++ )
{
if( i != p_region->fmt.i_visible_width &&
- p_data[i] == i_last_pixel && i_length != 1 )
+ p_data[i] == i_last_pixel && i_length != 280 )
{
i_length++;
continue;
}
- if( i_length == 1 )
+ if( i_length == 1 || (i_length == 3 && i_last_pixel) || i_length == 8 )
{
/* 4bit/pixel code */
if( i_last_pixel ) bs_write( s, 4, i_last_pixel );
bs_write( s, 1, 1 );
bs_write( s, 2, 0 ); /* pseudo color 0 */
}
+ i_length--;
+ }
+
+ if( i_length == 2 )
+ {
+ if( i_last_pixel )
+ {
+ bs_write( s, 4, i_last_pixel );
+ bs_write( s, 4, i_last_pixel );
+ }
+ else
+ {
+ bs_write( s, 4, 0 );
+ bs_write( s, 1, 1 );
+ bs_write( s, 1, 1 );
+ bs_write( s, 2, 1 ); /* 2 * pseudo color 0 */
+ }
+ }
+ else if( !i_last_pixel && i_length >= 3 && i_length <= 9 )
+ {
+ bs_write( s, 4, 0 );
+ bs_write( s, 1, 0 );
+ bs_write( s, 3, i_length - 2 ); /* (i_length - 2) * color 0 */
+ }
+ else if( i_length > 2 )
+ {
+ bs_write( s, 4, 0 );
+ bs_write( s, 1, 1 );
+
+ if( i_length <= 7 )
+ {
+ bs_write( s, 1, 0 );
+ bs_write( s, 2, i_length - 4 );
+ bs_write( s, 4, i_last_pixel );
+ }
+ else
+ {
+ bs_write( s, 1, 1 );
+
+ if( i_length <= 24 )
+ {
+ bs_write( s, 2, 2 );
+ bs_write( s, 4, i_length - 9 );
+ bs_write( s, 4, i_last_pixel );
+ }
+ else
+ {
+ bs_write( s, 2, 3 );
+ bs_write( s, 8, i_length - 25 );
+ bs_write( s, 4, i_last_pixel );
+ }
+ }
+ }
+
+ if( i == p_region->fmt.i_visible_width ) break;
+
+ i_last_pixel = p_data[i];
+ i_length = 1;
+ }
+
+ /* Stop */
+ bs_write( s, 8, 0 );
+
+ /* Stuffing */
+ bs_align_0( s );
+}
+
+static void encode_pixel_line_8bp( encoder_t *p_enc, bs_t *s,
+ subpicture_region_t *p_region,
+ int i_line )
+{
+ unsigned int i, i_length = 0;
+ int i_pitch = p_region->picture.p->i_pitch;
+ uint8_t *p_data = &p_region->picture.p->p_pixels[ i_pitch * i_line ];
+ int i_last_pixel = p_data[0];
+
+ for( i = 0; i <= p_region->fmt.i_visible_width; i++ )
+ {
+ if( i != p_region->fmt.i_visible_width &&
+ p_data[i] == i_last_pixel && i_length != 127 )
+ {
+ i_length++;
+ continue;
+ }
+
+ if( i_length == 1 && i_last_pixel )
+ {
+ /* 8bit/pixel code */
+ bs_write( s, 8, i_last_pixel );
+ }
+ else if( i_length == 2 && i_last_pixel )
+ {
+ /* 8bit/pixel code */
+ bs_write( s, 8, i_last_pixel );
+ bs_write( s, 8, i_last_pixel );
+ }
+ else if( i_length <= 127 )
+ {
+ bs_write( s, 8, 0 );
+
+ if( !i_last_pixel )
+ {
+ bs_write( s, 1, 0 );
+ bs_write( s, 7, i_length ); /* pseudo color 0 */
+ }
+ else
+ {
+ bs_write( s, 1, 1 );
+ bs_write( s, 7, i_length );
+ bs_write( s, 8, i_last_pixel );
+ }
}
if( i == p_region->fmt.i_visible_width ) break;
/* Stop */
bs_write( s, 8, 0 );
+ bs_write( s, 8, 0 );
/* Stuffing */
bs_align_0( s );