*
* Authors: Damien LUCAS <damien.lucas@anevia.com>
* Laurent Aimar <fenrir@via.ecp.fr>
+ * Gildas Bazin <gbazin@videolan.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
#include "vlc_bits.h"
+//#define DEBUG_DVBSUB 1
+
/*****************************************************************************
* Module descriptor.
*****************************************************************************/
/* Storage of a RLE entry */
typedef struct dvbsub_rle_s
{
- uint16_t i_num;
- uint8_t i_color_code;
+ uint16_t i_num;
+ int i_color_code;
+ int i_bpp;
uint8_t y;
uint8_t cr;
uint8_t cb;
uint8_t t;
- struct dvbsub_rle_s* p_next;
+ struct dvbsub_rle_s *p_next;
+
} dvbsub_rle_t;
/* A subpicture image is a list of codes
* We need to store the length of each line since nothing specify in
- * the standard that all lines shoudl have the same length
+ * the standard that all lines should have the same length
* WARNING: We assume here that a spu is less than 576 lines high */
typedef struct
{
- uint16_t i_rows;
- uint16_t i_cols[576];
- dvbsub_rle_t* p_last;
- dvbsub_rle_t* p_codes;
+ uint16_t i_rows;
+ uint16_t i_cols[576];
+ dvbsub_rle_t *p_last;
+ dvbsub_rle_t *p_codes;
} dvbsub_image_t;
/* The object definition gives the position of the object in a region */
typedef struct dvbsub_objectdef_s
{
- uint16_t i_id;
- uint8_t i_type;
- uint8_t i_provider;
- uint16_t i_xoffset;
- uint16_t i_yoffset;
- uint8_t i_fg_pc;
- uint8_t i_bg_pc;
- struct dvbsub_objectdef_s* p_next;
+ uint16_t i_id;
+ uint8_t i_type;
+ uint8_t i_provider;
+ uint16_t i_x;
+ uint16_t i_y;
+ uint8_t i_fg_pc;
+ uint8_t i_bg_pc;
} dvbsub_objectdef_t;
+/* An object is constituted of 2 images (for interleaving) */
+typedef struct dvbsub_object_s
+{
+ uint16_t i_id;
+ uint8_t i_version_number;
+ uint8_t i_coding_method;
+ vlc_bool_t b_non_modify_color;
+ dvbsub_image_t *topfield;
+ dvbsub_image_t *bottomfield;
+ struct dvbsub_object_s *p_next;
+
+} dvbsub_object_t;
+
+/* The object definition gives the position of the object in a region */
+typedef struct dvbsub_regiondef_s
+{
+ uint16_t i_id;
+ uint16_t i_x;
+ uint16_t i_y;
+
+} dvbsub_regiondef_t;
+
/* The Region is an aera on the image
- * with a list of the object definitions associated
- * and a CLUT */
+ * with a list of the object definitions associated and a CLUT */
typedef struct dvbsub_region_s
{
uint8_t i_id;
uint8_t i_8bp_code;
uint8_t i_4bp_code;
uint8_t i_2bp_code;
- dvbsub_objectdef_t* p_object;
+
+ int i_object_defs;
+ dvbsub_objectdef_t *p_object_defs;
+
+ struct dvbsub_region_s *p_next;
} dvbsub_region_t;
uint8_t i_timeout;
uint8_t i_state;
uint8_t i_version_number;
- uint8_t i_regions_number;
- dvbsub_region_t* regions;
-} dvbsub_page_t;
-
-/* An object is constituted of 2 images (for interleaving) */
-typedef struct dvbsub_object_s
-{
- uint16_t i_id;
- uint8_t i_version_number;
- uint8_t i_coding_method;
- vlc_bool_t b_non_modify_color;
- dvbsub_image_t* topfield;
- dvbsub_image_t* bottomfield;
- struct dvbsub_object_s* p_next;
+ uint8_t i_region_defs;
+ dvbsub_regiondef_t *p_region_defs;
-} dvbsub_object_t;
+} dvbsub_page_t;
/* The entry in the palette CLUT */
typedef struct
{
uint8_t i_id;
uint8_t i_version_number;
- dvbsub_color_t c_2b[0xff];
- dvbsub_color_t c_4b[0xff];
- dvbsub_color_t c_8b[0xff];
+ dvbsub_color_t c_2b[4];
+ dvbsub_color_t c_4b[16];
+ dvbsub_color_t c_8b[256];
} dvbsub_clut_t;
-typedef struct
-{
- uint8_t i_x;
- uint16_t i_y;
- dvbsub_image_t* p_rle_top;
- dvbsub_image_t* p_rle_bot;
-
-} dvbsub_render_t;
-
-typedef struct
+typedef struct dvbsub_render_s
{
- int i_id;
-
- mtime_t i_pts;
+ uint16_t i_x;
+ uint16_t i_y;
+ dvbsub_image_t *p_rle_top;
+ dvbsub_image_t *p_rle_bot;
- dvbsub_clut_t* p_clut[0xff];
- dvbsub_page_t* p_page;
- dvbsub_object_t* p_objects;
- subpicture_t* p_spu[16];
- int i_subpic_channel;
+ struct dvbsub_render_s *p_next;
-} dvbsub_all_t;
+} dvbsub_render_t;
struct subpicture_sys_t
{
- mtime_t i_pts;
- void * p_data; /* rle datas are stored */
- vlc_object_t* p_input; /* Link to the input */
- vlc_bool_t b_obsolete;
+ dvbsub_render_t *p_objects; /* Linked list of objects to render */
};
struct decoder_sys_t
{
- vout_thread_t *p_vout;
+ vout_thread_t *p_vout;
+
+ bs_t bs;
+
+ /* Decoder internal data */
+ int i_id;
+ int i_ancillary_id;
+
+ mtime_t i_pts;
- bs_t bs;
+ dvbsub_page_t *p_page;
+ dvbsub_region_t *p_regions;
+ dvbsub_object_t *p_objects;
- dvbsub_all_t dvbsub;
+ dvbsub_clut_t *p_clut[256];
+ dvbsub_clut_t default_clut;
+
+ subpicture_t *p_spu;
+ int i_subpic_channel;
};
#define DVBSUB_DT_28_TABLE_DATA 0x21
#define DVBSUB_DT_48_TABLE_DATA 0x22
#define DVBSUB_DT_END_LINE 0xf0
+// List of different Page Composition Segment state
+// According to EN 300-743, 7.2.1 table 3
+#define DVBSUB_PCS_STATE_ACQUISITION 0x01
+#define DVBSUB_PCS_STATE_CHANGE 0x10
/*****************************************************************************
* Local prototypes
*****************************************************************************/
-static void Decode ( decoder_t *, block_t ** );
+static void Decode( decoder_t *, block_t ** );
+
+static void decode_segment( decoder_t *, bs_t * );
+static void decode_page_composition( decoder_t *, bs_t * );
+static void decode_region_composition( decoder_t *, bs_t * );
+static void decode_object( decoder_t *, bs_t * );
+static void decode_clut( decoder_t *, bs_t * );
-static vout_thread_t *FindVout( decoder_t * );
+static void free_objects( decoder_t * );
+static void free_all( decoder_t * );
-static int init( dvbsub_all_t *, int );
-static void decode_segment( decoder_t *, dvbsub_all_t *, bs_t * );
-static void render( dvbsub_all_t *, vout_thread_t * );
-static void dvbsub( dvbsub_all_t * );
+static void render( decoder_t *, vout_thread_t * );
+static void default_clut_init( decoder_t * );
/*****************************************************************************
* Open: probe the decoder and return score
*****************************************************************************/
static int Open( vlc_object_t *p_this )
{
- decoder_t *p_dec = (decoder_t*) p_this;
+ decoder_t *p_dec = (decoder_t *) p_this;
decoder_sys_t *p_sys;
+ int i;
if( p_dec->fmt_in.i_codec != VLC_FOURCC('d','v','b','s') )
{
p_dec->pf_decode_sub = Decode;
p_sys = p_dec->p_sys = malloc( sizeof(decoder_sys_t) );
- p_sys->p_vout = NULL;
-
- init( &p_sys->dvbsub, p_dec->fmt_in.subs.dvb.i_id );
+ 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_page = NULL;
+ p_sys->p_regions = NULL;
+ p_sys->p_objects = NULL;
+ p_sys->p_vout = NULL;
+ p_sys->p_spu = NULL;
+ for( i = 0; i < 256; i++ ) p_sys->p_clut[i] = NULL;
es_format_Init( &p_dec->fmt_out, SPU_ES, VLC_FOURCC( 'd','v','b','s' ) );
+ default_clut_init( p_dec );
+
return VLC_SUCCESS;
}
if( p_sys->p_vout && p_sys->p_vout->p_subpicture != NULL )
{
- subpicture_t * p_subpic;
+ subpicture_t *p_subpic;
int i_subpic;
for( i_subpic = 0; i_subpic < VOUT_MAX_SUBPICTURES; i_subpic++ )
{
}
}
- dvbsub( &p_sys->dvbsub );
-
+ free_all( p_dec );
free( p_sys );
}
p_block = *pp_block;
*pp_block = NULL;
- p_sys->dvbsub.i_pts = p_block->i_pts;
- if( p_sys->dvbsub.i_pts <= 0 )
+ p_sys->i_pts = p_block->i_pts;
+ if( p_sys->i_pts <= 0 )
{
msg_Warn( p_dec, "non dated subtitle" );
block_Release( p_block );
return;
}
- p_last_vout = p_sys->p_vout;
- if( ( p_sys->p_vout = FindVout( p_dec ) ) )
+ bs_init( &p_sys->bs, p_block->p_buffer, p_block->i_buffer );
+
+ if( bs_read( &p_sys->bs, 8 ) != 0x20 ) /* Data identifier */
{
- int i_data_identifier;
- int i_subtitle_stream_id;
- int i_end_data_marker;
+ msg_Dbg( p_dec, "invalid data identifier" );
+ block_Release( p_block );
+ return;
+ }
- bs_init( &p_sys->bs, p_block->p_buffer, p_block->i_buffer );
+ if( bs_read( &p_sys->bs, 8 ) != 0x20 && 0 ) /* Subtitle stream id */
+ {
+ msg_Dbg( p_dec, "invalid subtitle stream id" );
+ block_Release( p_block );
+ return;
+ }
- i_data_identifier = bs_read( &p_sys->bs, 8 );
- i_subtitle_stream_id = bs_read( &p_sys->bs, 8 );
+ while( bs_show( &p_sys->bs, 8 ) == 0x0f ) /* Sync byte */
+ {
+ decode_segment( p_dec, &p_sys->bs );
+ }
- for( ;; )
- {
- if( bs_show( &p_sys->bs, 8 ) != 0x0f )
- {
- break;
- }
- decode_segment( p_dec, &p_sys->dvbsub, &p_sys->bs );
- }
- i_end_data_marker = bs_read( &p_sys->bs, 8 );
+ if( bs_read( &p_sys->bs, 8 ) != 0xff ) /* End marker */
+ {
+ msg_Warn( p_dec, "end marker not found (corrupted subtitle ?)" );
+ block_Release( p_block );
+ return;
+ }
+ p_last_vout = p_sys->p_vout;
+ if( ( p_sys->p_vout = vlc_object_find( p_dec, VLC_OBJECT_VOUT,
+ FIND_ANYWHERE ) ) )
+ {
if( p_last_vout != p_sys->p_vout )
{
- p_sys->dvbsub.i_subpic_channel =
+ p_sys->i_subpic_channel =
vout_RegisterOSDChannel( p_sys->p_vout );
}
/* Check if the page is to be displayed */
- if( p_sys->dvbsub.p_page && p_sys->dvbsub.p_objects )
- {
- render( &p_sys->dvbsub, p_sys->p_vout );
- }
+ if( p_sys->p_page ) render( p_dec, p_sys->p_vout );
vlc_object_release( p_sys->p_vout );
}
+#ifdef DEBUG_DVBSUB
+ else if( p_sys->p_page ) render( p_dec, NULL );
+#endif
block_Release( p_block );
}
/* following functions are local */
+
/*****************************************************************************
- * FindVout: Find a vout or wait for one to be created.
+ * default_clut_init: default clut as defined in EN 300-743 section 10
*****************************************************************************/
-static vout_thread_t *FindVout( decoder_t *p_dec )
+static void default_clut_init( decoder_t *p_dec )
{
- for( ;; )
- {
- vout_thread_t *p_vout;
+ decoder_sys_t *p_sys = p_dec->p_sys;
+ uint8_t i;
- if( p_dec->b_die || p_dec->b_error )
- {
- return NULL;
- }
- p_vout = vlc_object_find( p_dec, VLC_OBJECT_VOUT, FIND_ANYWHERE );
- if( p_vout )
- {
- return p_vout;
- }
- msleep( VOUT_OUTMEM_SLEEP );
- }
-}
+#define RGB_TO_Y(r, g, b) ((int16_t) 77 * r + 150 * g + 29 * b) / 256;
+#define RGB_TO_U(r, g, b) ((int16_t) -44 * r - 87 * g + 131 * b) / 256;
+#define RGB_TO_V(r, g, b) ((int16_t) 131 * r - 110 * g - 21 * b) / 256;
-static int init( dvbsub_all_t *p_dvbsub, int i_id )
-{
- int i;
+ /* 4 entries CLUT */
+ for( i = 0; i < 4; i++ )
+ {
+ uint8_t R = 0, G = 0, B = 0, T = 0;
- memset( p_dvbsub, 0, sizeof( dvbsub_all_t ) );
+ if( !(i & 0x2) && !(i & 0x1) ) T = 0xFF;
+ else if( !(i & 0x2) && (i & 0x1) ) R = G = B = 0xFF;
+ else if( (i & 0x2) && !(i & 0x1) ) R = G = B = 0;
+ else R = G = B = 0x7F;
- p_dvbsub->i_pts = 0;
- p_dvbsub->i_id = i_id;
- p_dvbsub->p_page = NULL;
- p_dvbsub->p_objects = NULL;
- for( i = 0; i < 255; i++ )
- {
- p_dvbsub->p_clut[i] = NULL;
+ p_sys->default_clut.c_2b[i].Y = RGB_TO_Y(R,G,B);
+ p_sys->default_clut.c_2b[i].Cr = RGB_TO_U(R,G,B);
+ p_sys->default_clut.c_2b[i].Cb = RGB_TO_V(R,G,B);
+ p_sys->default_clut.c_2b[i].T = T;
}
+
+ /* 16 entries CLUT */
for( i = 0; i < 16; i++ )
{
- p_dvbsub->p_spu[i] = NULL;
- }
- return 0;
-}
-
-static void free_all( dvbsub_all_t * );
+ uint8_t R = 0, G = 0, B = 0, T = 0;
-static void dvbsub( dvbsub_all_t *p_dvbsub )
-{
- free_all( p_dvbsub );
-}
+ if( !(i & 0x8) )
+ {
+ if( !(i & 0x4) && !(i & 0x2) && !(i & 0x1) )
+ {
+ T = 0xFF;
+ }
+ else
+ {
+ R = (i & 0x1) ? 0xFF : 0;
+ G = (i & 0x2) ? 0xFF : 0;
+ B = (i & 0x4) ? 0xFF : 0;
+ }
+ }
+ else
+ {
+ R = (i & 0x1) ? 0x7F : 0;
+ G = (i & 0x2) ? 0x7F : 0;
+ B = (i & 0x4) ? 0x7F : 0;
+ }
-static void decode_clut( dvbsub_all_t *p_dvbsub, bs_t *s );
-static void decode_page_composition( dvbsub_all_t *p_dvbsub, bs_t *s);
-static void decode_region_composition( dvbsub_all_t *p_dvbsub, bs_t *s );
-static void stop_display( dvbsub_all_t* p_dvbsub );
-static void decode_object( dvbsub_all_t *p_dvbsub, bs_t *s );
+ p_sys->default_clut.c_4b[i].Y = RGB_TO_Y(R,G,B);
+ p_sys->default_clut.c_4b[i].Cr = RGB_TO_U(R,G,B);
+ p_sys->default_clut.c_4b[i].Cb = RGB_TO_V(R,G,B);
+ p_sys->default_clut.c_4b[i].T = T;
+ }
-static void free_page( dvbsub_page_t* p_p );
+ /* 256 entries CLUT (TODO) */
+ memset( p_sys->default_clut.c_8b, 0xFF, 256 * sizeof(dvbsub_color_t) );
+}
-static void decode_segment( decoder_t *p_dec, dvbsub_all_t *p_dvbspu, bs_t *s )
+static void decode_segment( decoder_t *p_dec, bs_t *s )
{
+ decoder_sys_t *p_sys = p_dec->p_sys;
int i_type;
int i_page_id;
int i_size;
- /* sync_byte */
+ /* sync_byte (already checked) */
bs_skip( s, 8 );
/* segment type */
/* segment size */
i_size = bs_show( s, 16 );
- if( i_page_id != p_dvbspu->i_id )
+ if( i_page_id != p_sys->i_id && i_page_id != p_sys->i_ancillary_id )
{
+#ifdef DEBUG_DVBSUB
+ msg_Dbg( p_dec, "subtitle skipped (page id: %i)", i_page_id );
+#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 );
+ else
+ msg_Dbg( p_dec, "ancillary segment (id: %i)", i_page_id );
+#endif
+
switch( i_type )
{
- case DVBSUB_ST_CLUT_DEFINITION:
+ case DVBSUB_ST_PAGE_COMPOSITION:
#ifdef DEBUG_DVBSUB
- msg_Dbg( p_dec, "subtitle dvbsub_decode_clut" );
+ msg_Dbg( p_dec, "decode_page_composition" );
#endif
- decode_clut( p_dvbspu, s );
+ decode_page_composition( p_dec, s );
break;
- case DVBSUB_ST_PAGE_COMPOSITION:
+
+ case DVBSUB_ST_REGION_COMPOSITION:
#ifdef DEBUG_DVBSUB
- msg_Dbg( p_dec, "subtitle dvbsub_decode_page_composition" );
+ msg_Dbg( p_dec, "decode_region_composition" );
#endif
- decode_page_composition( p_dvbspu, s );
+ decode_region_composition( p_dec, s );
break;
- case DVBSUB_ST_REGION_COMPOSITION:
+
+ case DVBSUB_ST_CLUT_DEFINITION:
#ifdef DEBUG_DVBSUB
- msg_Dbg( p_dec, "subtitle dvbsub_decode_region_composition" );
+ msg_Dbg( p_dec, "decode_clut" );
#endif
- decode_region_composition( p_dvbspu, s );
+ decode_clut( p_dec, s );
break;
+
case DVBSUB_ST_OBJECT_DATA:
#ifdef DEBUG_DVBSUB
- msg_Dbg( p_dec, "subtitle dvbsub_decode_object" );
+ msg_Dbg( p_dec, "decode_object" );
#endif
- decode_object( p_dvbspu, s );
+ decode_object( p_dec, s );
break;
+
case DVBSUB_ST_ENDOFDISPLAY:
#ifdef DEBUG_DVBSUB
- msg_Dbg( p_dec, "subtitle dvbsub_stop_display" );
+ msg_Dbg( p_dec, "end of display" );
#endif
- stop_display( p_dvbspu );
+ bs_skip( s, 8 * ( 2 + i_size ) );
break;
+
case DVBSUB_ST_STUFFING:
+#ifdef DEBUG_DVBSUB
+ msg_Dbg( p_dec, "skip stuffing" );
+#endif
+ bs_skip( s, 8 * ( 2 + i_size ) );
+ break;
+
default:
msg_Warn( p_dec, "unsupported segment type: (%04x)", i_type );
bs_skip( s, 8 * ( 2 + i_size ) );
}
}
-static void stop_display( dvbsub_all_t *p_dvbsub )
-{
- int i;
-
- for( i = 0; p_dvbsub->p_spu[i] != NULL; i++ )
- {
- p_dvbsub->p_spu[i]->i_stop = p_dvbsub->i_pts;
- }
-}
-
-static void decode_clut( dvbsub_all_t *p_dvbsub, bs_t *s )
+static void decode_clut( decoder_t *p_dec, bs_t *s )
{
- uint16_t i_segment_length;
- uint16_t i_processed_length;
- dvbsub_clut_t* clut;
- uint8_t i_clut_id;
- uint8_t i_version_number;
+ decoder_sys_t *p_sys = p_dec->p_sys;
+ uint16_t i_segment_length;
+ uint16_t i_processed_length;
+ dvbsub_clut_t *p_clut;
+ uint8_t i_clut_id;
+ uint8_t i_version_number;
i_segment_length = bs_read( s, 16 );
i_clut_id = bs_read( s, 8 );
i_version_number = bs_read( s, 4 );
- // Check that this id doesn't not already exist
- // with the same version number
- // And allocate memory if necessary
- if( p_dvbsub->p_clut[i_clut_id] != NULL)
+ /* Check that this id doesn't not already exist with the same version
+ * number and allocate memory if necessary */
+ if( p_sys->p_clut[i_clut_id] != NULL &&
+ p_sys->p_clut[i_clut_id]->i_version_number == i_version_number )
{
- if( p_dvbsub->p_clut[i_clut_id]->i_version_number == i_version_number )
- {
- //TODO skip the right number of bits
- return;
- }
- else
- {
- memset( p_dvbsub->p_clut[i_clut_id], 0, sizeof(dvbsub_clut_t) );
- }
+ /* Nothing to do */
+ bs_skip( s, 8 * i_segment_length - 12 );
+ return;
}
- else
+
+ if( !p_sys->p_clut[i_clut_id] )
{
- p_dvbsub->p_clut[i_clut_id] = malloc( sizeof(dvbsub_clut_t) );
+ p_sys->p_clut[i_clut_id] = malloc( sizeof(dvbsub_clut_t) );
}
- clut = p_dvbsub->p_clut[i_clut_id];
+
+ p_clut = p_sys->p_clut[i_clut_id];
/* We don't have this version of the CLUT: Parse it */
- clut->i_version_number = i_version_number;
+ p_clut->i_version_number = i_version_number;
bs_skip( s, 4 ); /* Reserved bits */
i_processed_length = 2;
while( i_processed_length < i_segment_length )
}
/* According to EN 300-743 section 7.2.3 note 1, type should
- * not have more than 1 bit set to one
- But, some strams don't respect this note. */
+ * not have more than 1 bit set to one, but some strams don't
+ * respect this note. */
if( i_type&0x04)
{
- clut->c_2b[i_id].Y = y;
- clut->c_2b[i_id].Cr = cr;
- clut->c_2b[i_id].Cb = cb;
- clut->c_2b[i_id].T = t;
+ 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)
{
- clut->c_4b[i_id].Y = y;
- clut->c_4b[i_id].Cr = cr;
- clut->c_4b[i_id].Cb = cb;
- clut->c_4b[i_id].T = t;
+ 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)
{
- clut->c_8b[i_id].Y = y;
- clut->c_8b[i_id].Cr = cr;
- clut->c_8b[i_id].Cb = cb;
- clut->c_8b[i_id].T = t;
+ p_clut->c_8b[i_id].Y = y;
+ p_clut->c_8b[i_id].Cr = cr;
+ p_clut->c_8b[i_id].Cb = cb;
+ p_clut->c_8b[i_id].T = t;
}
}
}
-static void decode_page_composition( dvbsub_all_t *p_dvbsub, bs_t *s )
+static void decode_page_composition( decoder_t *p_dec, bs_t *s )
{
+ decoder_sys_t *p_sys = p_dec->p_sys;
unsigned int i_version_number;
unsigned int i_state;
unsigned int i_segment_length;
uint8_t i_timeout;
unsigned int i;
- i_segment_length = bs_read( s, 16 );
+ /* A page is composed by one or more region */
- /* A page is composed by one or more region: */
+ i_segment_length = bs_read( s, 16 );
i_timeout = bs_read( s, 8 );
i_version_number = bs_read( s, 4 );
i_state = bs_read( s, 2 );
-
- /* TODO We assume it is a new page (i_state) */
- if( p_dvbsub->p_page ) free_page( p_dvbsub->p_page );
-
bs_skip( s, 2 ); /* Reserved */
- /* Allocate a new page */
- p_dvbsub->p_page = malloc( sizeof(dvbsub_page_t) );
- p_dvbsub->p_page->i_timeout = i_timeout;
+ if( i_state == DVBSUB_PCS_STATE_CHANGE )
+ {
+ /* End of an epoch, reset decoder buffer */
+#ifdef DEBUG_DVBSUB
+ msg_Dbg( p_dec, "page composition mode change" );
+#endif
+ free_all( p_dec );
+ }
+ else if( !p_sys->p_page && i_state != DVBSUB_PCS_STATE_ACQUISITION )
+ {
+ /* Not a full PCS, we need to wait for one */
+ return;
+ }
+
+ if( i_state == DVBSUB_PCS_STATE_ACQUISITION )
+ {
+ /* Make sure we clean up regularly our objects list.
+ * Is it the best place to do this ? */
+ free_objects( p_dec );
+ }
- /* Number of regions: */
- p_dvbsub->p_page->i_regions_number = (i_segment_length-2) / 6;
+ /* Check version number */
+ if( p_sys->p_page &&
+ p_sys->p_page->i_version_number == i_version_number )
+ {
+ bs_skip( s, 8 * (i_segment_length - 2) );
+ return;
+ }
+ else if( p_sys->p_page )
+ {
+ if( p_sys->p_page->i_region_defs )
+ free( p_sys->p_page->p_region_defs );
+ p_sys->p_page->i_region_defs = 0;
+ }
- /* Special workaround for CAVENA encoders: a page with no regions is sent
- * instead of a 0x80 packet (End Of Display) */
- if( p_dvbsub->p_page->i_regions_number == 0 )
+ if( !p_sys->p_page )
{
- stop_display( p_dvbsub );
+ /* Allocate a new page */
+ p_sys->p_page = malloc( sizeof(dvbsub_page_t) );
}
- /* End of workaround */
- p_dvbsub->p_page->regions =
- malloc( p_dvbsub->p_page->i_regions_number * sizeof(dvbsub_region_t) );
- for( i = 0; i < p_dvbsub->p_page->i_regions_number; i++ )
+ p_sys->p_page->i_version_number = i_version_number;
+ p_sys->p_page->i_timeout = i_timeout;
+
+ /* Number of regions */
+ p_sys->p_page->i_region_defs = (i_segment_length - 2) / 6;
+
+ if( p_sys->p_page->i_region_defs == 0 ) return;
+
+ p_sys->p_page->p_region_defs =
+ malloc( p_sys->p_page->i_region_defs * sizeof(dvbsub_region_t) );
+ for( i = 0; i < p_sys->p_page->i_region_defs; i++ )
{
- p_dvbsub->p_page->regions[i].i_id = bs_read( s, 8 );
+ p_sys->p_page->p_region_defs[i].i_id = bs_read( s, 8 );
bs_skip( s, 8 ); /* Reserved */
- p_dvbsub->p_page->regions[i].i_x = bs_read( s, 16 );
- p_dvbsub->p_page->regions[i].i_y = bs_read( s, 16 );
- p_dvbsub->p_page->regions[i].p_object = NULL;
+ p_sys->p_page->p_region_defs[i].i_x = bs_read( s, 16 );
+ p_sys->p_page->p_region_defs[i].i_y = bs_read( s, 16 );
+
+#ifdef DEBUG_DVBSUB
+ msg_Dbg( p_dec, "page_composition, region %i (%i,%i)",
+ i, p_sys->p_page->p_region_defs[i].i_x,
+ p_sys->p_page->p_region_defs[i].i_y );
+#endif
}
}
-
-static void decode_region_composition( dvbsub_all_t *p_dvbsub, bs_t *s )
+static void decode_region_composition( decoder_t *p_dec, bs_t *s )
{
- dvbsub_region_t* p_region = NULL;
- unsigned int i_segment_length;
- unsigned int i_processed_length;
- unsigned int i_region_id;
- unsigned int i;
+ decoder_sys_t *p_sys = p_dec->p_sys;
+ dvbsub_region_t *p_region, **pp_region = &p_sys->p_regions;
+ int i_segment_length;
+ int i_processed_length;
+ int i_region_id;
+ int i_version_number;
i_segment_length = bs_read( s, 16 );
-
- /* Get region id: */
i_region_id = bs_read( s, 8 );
- for( i = 0; i < p_dvbsub->p_page->i_regions_number; i++ )
+ i_version_number = bs_read( s, 4 );
+
+ /* Check if we already have this region */
+ for( p_region = p_sys->p_regions; p_region != NULL;
+ p_region = p_region->p_next )
{
- if( p_dvbsub->p_page->regions[i].i_id == i_region_id )
- {
- p_region = &(p_dvbsub->p_page->regions[i]);
- }
+ pp_region = &p_region->p_next;
+ if( p_region->i_id == i_region_id ) break;
}
- if( p_region == NULL )
+ /* Check version number */
+ if( p_region &&
+ p_region->i_version_number == i_version_number )
{
- /* TODO
- * The region has never been declared before
- * Internal error */
- fprintf( stderr, "Decoding of undeclared region N/A\n" );
+ bs_skip( s, 8 * (i_segment_length - 1) - 4 );
return;
}
+ else if( p_region )
+ {
+ if( p_region->i_object_defs )
+ free( p_region->p_object_defs );
+ }
- /* Skip version number and fill flag */
- if( bs_show( s, 4 ) == p_region->i_version_number )
+ if( !p_region )
{
- fprintf( stderr, "Skipping already known region N/A\n" );
- /* TODO Skip the right number of bits */
+#ifdef DEBUG_DVBSUB
+ msg_Dbg( p_dec, "new region: %i", i_region_id );
+#endif
+ p_region = *pp_region = malloc( sizeof(dvbsub_region_t) );
+ p_region->p_next = NULL;
}
/* Region attributes */
- p_region->i_version_number = bs_read( s, 4 );
+ p_region->i_id = i_region_id;
+ p_region->i_version_number = i_version_number;
p_region->b_fill = bs_read( s, 1 );
bs_skip( s, 3 ); /* Reserved */
p_region->i_width = bs_read( s, 16 );
p_region->i_4bp_code = bs_read( s, 4 );
p_region->i_2bp_code = bs_read( s, 2 );
bs_skip( s, 2 ); /* Reserved */
+ p_region->p_object_defs = NULL;
+ p_region->i_object_defs = 0;
- /* List of objects in the region: */
- /* We already skipped 10 bytes */
-
+ /* List of objects in the region */
i_processed_length = 10;
while( i_processed_length < i_segment_length )
{
+ dvbsub_objectdef_t *p_obj;
+
/* We create a new object */
- dvbsub_objectdef_t *p_obj = malloc( sizeof(dvbsub_objectdef_t) );
+ p_region->i_object_defs++;
+ p_region->p_object_defs =
+ realloc( p_region->p_object_defs,
+ sizeof(dvbsub_objectdef_t) * p_region->i_object_defs );
/* We parse object properties */
- p_obj->p_next = NULL;
+ p_obj = &p_region->p_object_defs[p_region->i_object_defs - 1];
p_obj->i_id = bs_read( s, 16 );
p_obj->i_type = bs_read( s, 2 );
p_obj->i_provider = bs_read( s, 2 );
- p_obj->i_xoffset = bs_read( s, 12 );
+ p_obj->i_x = bs_read( s, 12 );
bs_skip( s, 4 ); /* Reserved */
- p_obj->i_yoffset = bs_read( s, 12 );
+ p_obj->i_y = bs_read( s, 12 );
i_processed_length += 6;
p_obj->i_bg_pc = bs_read( s, 8 );
i_processed_length += 2;
}
-
- /* we append it */
- if( p_region->p_object )
- {
- dvbsub_objectdef_t *p_o;
- for( p_o = p_region->p_object; ; p_o = p_o->p_next )
- {
- if( p_o->p_next == NULL )
- {
- break;
- }
- }
- p_o->p_next = p_obj;
- }
- else
- {
- p_region->p_object = p_obj;
- }
}
}
-static dvbsub_image_t* dvbsub_parse_pdata( dvbsub_all_t *p_dvbsub, bs_t *s,
- uint16_t length );
-static uint16_t dvbsub_count0x11( bs_t *s, uint16_t* p,
- dvbsub_image_t* p_image);
+static dvbsub_image_t *dvbsub_parse_pdata( decoder_t *, bs_t *, uint16_t );
+static uint16_t dvbsub_pdata2bpp( bs_t *, uint16_t *, dvbsub_image_t * );
+static uint16_t dvbsub_pdata4bpp( bs_t *, uint16_t *, dvbsub_image_t * );
+static uint16_t dvbsub_pdata8bpp( bs_t *, uint16_t *, dvbsub_image_t * );
-static void decode_object( dvbsub_all_t *p_dvbsub, bs_t *s )
+static void decode_object( decoder_t *p_dec, bs_t *s )
{
- dvbsub_object_t *p_obj;
- uint16_t i_segment_length;
+ decoder_sys_t *p_sys = p_dec->p_sys;
+ dvbsub_object_t *p_obj, **pp_obj = &p_sys->p_objects;
+ int i_segment_length;
+ int i_version_number;
+ int i_coding_method;
+ int i_obj_id;
+
+ i_segment_length = bs_read( s, 16 );
+ i_obj_id = bs_read( s, 16 );
+ i_version_number = bs_read( s, 4 );
+ i_coding_method = bs_read( s, 2 );
+
+ if( i_coding_method )
+ {
+ /* TODO: DVB subtitling as characters */
+ msg_Dbg( p_dec, "DVB subtitling as characters is not handled!" );
+ bs_skip( s, 8 * (i_segment_length - 2) - 6 );
+ return;
+ }
- /* Memory Allocation */
- p_obj = malloc( sizeof(dvbsub_object_t) );
- p_obj->p_next = NULL;
+ /* Check if we already have this region */
+ for( p_obj = p_sys->p_objects; p_obj != NULL; p_obj = p_obj->p_next )
+ {
+ pp_obj = &p_obj->p_next;
+ if( p_obj->i_id == i_obj_id ) break;
+ }
- i_segment_length = bs_read( s, 16 );
+ /* Check version number */
+ if( p_obj && p_obj->i_version_number == i_version_number )
+ {
+ bs_skip( s, 8 * (i_segment_length - 2) - 6 );
+ return;
+ }
+ else if( p_obj )
+ {
+ /* Clean structure */
+ }
+
+ if( !p_obj )
+ {
+#ifdef DEBUG_DVBSUB
+ msg_Dbg( p_dec, "new object: %i", i_obj_id );
+#endif
+ p_obj = *pp_obj = malloc( sizeof(dvbsub_object_t) );
+ p_obj->p_next = NULL;
+ }
- /* TODO Check we don't already have this object / this version */
- p_obj->i_id = bs_read( s, 16 );
- p_obj->i_version_number = bs_read( s, 4 );
- p_obj->i_coding_method = bs_read( s, 2 );
- p_obj->b_non_modify_color= bs_read( s, 1 );
+ p_obj->i_id = i_obj_id;
+ p_obj->i_version_number = i_version_number;
+ p_obj->i_coding_method = i_coding_method;
+ p_obj->b_non_modify_color = bs_read( s, 1 );
bs_skip( s, 1 ); /* Reserved */
if( p_obj->i_coding_method == 0x00 )
i_bottomfield_length = bs_read( s, 16 );
p_obj->topfield =
- dvbsub_parse_pdata( p_dvbsub, s, i_topfield_length );
+ dvbsub_parse_pdata( p_dec, s, i_topfield_length );
p_obj->bottomfield =
- dvbsub_parse_pdata( p_dvbsub, s, i_bottomfield_length );
+ dvbsub_parse_pdata( p_dec, s, i_bottomfield_length );
}
else
{
- bs_skip( s, (i_segment_length - 3 ) * 8 );
- /*TODO: DVB subtitling as characters */
+ /* TODO: DVB subtitling as characters */
}
-
- /* Add this object to the list of the page */
- p_obj->p_next = p_dvbsub->p_objects;
- p_dvbsub->p_objects = p_obj;
}
-static dvbsub_image_t* dvbsub_parse_pdata( dvbsub_all_t *p_dvbsub, bs_t *s,
+static dvbsub_image_t* dvbsub_parse_pdata( decoder_t *p_dec, bs_t *s,
uint16_t length )
{
dvbsub_image_t* p_image;
/* Let's parse it a first time to determine the size of the buffer */
while( i_processed_length < length)
{
+ i_processed_length++;
+
switch( bs_read( s, 8 ) )
{
case 0x10:
- fprintf(stderr, "0x10 N/A\n");
+ i_processed_length +=
+ dvbsub_pdata2bpp( s, &p_image->i_cols[i_lines], p_image );
break;
case 0x11:
i_processed_length +=
- 1 + dvbsub_count0x11( s, &(p_image->i_cols[i_lines]),
- p_image );
+ dvbsub_pdata4bpp( s, &p_image->i_cols[i_lines], p_image );
break;
case 0x12:
- fprintf(stderr, "0x12 N/A\n");
+ i_processed_length +=
+ dvbsub_pdata8bpp( s, &p_image->i_cols[i_lines], p_image );
break;
case 0x20:
- fprintf(stderr, "0x20 N/A\n");
- break;
case 0x21:
- fprintf(stderr, "0x21 N/A\n");
- break;
case 0x22:
- fprintf(stderr, "0x22 N/A\n");
+ /* We don't use map tables */
break;
case 0xf0:
- i_processed_length++;
- i_lines++;
+ i_lines++; /* End of line code */
break;
}
}
return p_image;
}
-static void add_rle_code( dvbsub_image_t *p, uint16_t num, uint8_t color )
+static void add_rle_code( dvbsub_image_t *p, uint16_t num, uint8_t color,
+ int i_bpp )
{
- if(p->p_last != NULL)
+ if( p->p_last != NULL )
{
p->p_last->p_next = malloc( sizeof(dvbsub_rle_t) );
p->p_last = p->p_last->p_next;
}
else
{
- p->p_codes = malloc( sizeof(dvbsub_rle_t) );
+ p->p_codes = malloc( sizeof(dvbsub_rle_t) );
p->p_last = p->p_codes;
}
p->p_last->i_num = num;
+
p->p_last->i_color_code = color;
+ p->p_last->i_bpp = i_bpp;
p->p_last->p_next = NULL;
}
-static uint16_t dvbsub_count0x11( bs_t *s, uint16_t* p,
+static uint16_t dvbsub_pdata2bpp( bs_t *s, uint16_t* p,
+ dvbsub_image_t* p_image )
+{
+ uint16_t i_processed = 0;
+ vlc_bool_t b_stop = 0;
+ uint16_t i_count = 0;
+ uint8_t i_color = 0;
+
+ while( !b_stop )
+ {
+ i_processed += 2;
+ if( (i_color = bs_read( s, 2 )) != 0x00 )
+ {
+ (*p)++;
+
+ /* Add 1 pixel */
+ add_rle_code( p_image, 1, i_color, 2 );
+ }
+ else
+ {
+ i_processed++;
+ if( bs_read( s, 1 ) == 0x00 ) // Switch1
+ {
+ i_count = 3 + bs_read( s, 3 );
+ (*p) += i_count ;
+ i_color = bs_read( s, 2 );
+ add_rle_code( p_image, i_count, i_color, 2 );
+ i_processed += 5;
+ }
+ else
+ {
+ i_processed++;
+ if( bs_read( s, 1 ) == 0x00 ) //Switch2
+ {
+ i_processed += 2;
+ switch( bs_read( s, 2 ) ) //Switch3
+ {
+ case 0x00:
+ b_stop=1;
+ break;
+ case 0x01:
+ add_rle_code( p_image, 2, 0, 2 );
+ break;
+ case 0x02:
+ i_count = 12 + bs_read( s, 4 );
+ i_color = bs_read( s, 2 );
+ (*p) += i_count;
+ i_processed += 6;
+ add_rle_code( p_image, i_count, i_color, 2 );
+ break;
+ case 0x03:
+ i_count = 29 + bs_read( s, 8 );
+ i_color = bs_read( s, 2 );
+ (*p) += i_count;
+ i_processed += 10;
+ add_rle_code( p_image, i_count, i_color, 2 );
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ bs_align( s );
+
+ return ( i_processed + 7 ) / 8 ;
+}
+
+static uint16_t dvbsub_pdata4bpp( bs_t *s, uint16_t* p,
dvbsub_image_t* p_image )
{
- uint16_t i_processed=0;
- vlc_bool_t b_stop=0;
+ uint16_t i_processed = 0;
+ vlc_bool_t b_stop = 0;
uint16_t i_count = 0;
- uint8_t i_color =0;
+ uint8_t i_color = 0;
- while (!b_stop)
+ while( !b_stop )
{
if( (i_color = bs_read( s, 4 )) != 0x00 )
{
(*p)++;
i_processed+=4;
- /* 1 pixel of color code '0000' */
- add_rle_code( p_image, 1, i_color );
+ /* Add 1 pixel */
+ add_rle_code( p_image, 1, i_color, 4 );
}
else
{
{
i_count = 2 + bs_read( s, 3 );
(*p) += i_count ;
- add_rle_code( p_image, i_count, 0x00 );
+ add_rle_code( p_image, i_count, 0x00, 4 );
}
else
{
i_color = bs_read( s, 4 );
(*p) += i_count;
i_processed += 12;
- add_rle_code( p_image, i_count, i_color );
+ add_rle_code( p_image, i_count, i_color, 4 );
}
else
{
case 0x0:
(*p)++;
i_processed += 8;
- add_rle_code( p_image, 1, 0x00 );
+ add_rle_code( p_image, 1, 0x00, 4 );
break;
case 0x1:
(*p)+=2;
i_processed += 8;
- add_rle_code( p_image, 2, 0x00 );
+ add_rle_code( p_image, 2, 0x00, 4 );
break;
case 0x2:
i_count = 9 + bs_read( s, 4 );
i_color = bs_read( s, 4 );
(*p)+= i_count;
i_processed += 16;
- add_rle_code( p_image, i_count, i_color );
+ add_rle_code( p_image, i_count, i_color, 4 );
break;
case 0x3:
i_count= 25 + bs_read( s, 8 );
i_color = bs_read( s, 4 );
(*p)+= i_count;
i_processed += 20;
- add_rle_code( p_image, i_count, i_color );
+ add_rle_code( p_image, i_count, i_color, 4 );
break;
}
}
return ( i_processed + 7 ) / 8 ;
}
-static void free_image (dvbsub_image_t* p_i)
+static uint16_t dvbsub_pdata8bpp( bs_t *s, uint16_t* p,
+ dvbsub_image_t* p_image )
{
- dvbsub_rle_t* p1;
- dvbsub_rle_t* p2=NULL;
+ uint16_t i_processed = 0;
+ vlc_bool_t b_stop = 0;
+ uint16_t i_count = 0;
+ uint8_t i_color = 0;
- for( p1 = p_i->p_codes; p1 != NULL; p1=p2)
+ while( !b_stop )
{
- p2=p1->p_next;
- free(p1);
- p1=NULL;
+ i_processed += 8;
+ if( (i_color = bs_read( s, 8 )) != 0x00 )
+ {
+ (*p)++;
+
+ /* Add 1 pixel */
+ add_rle_code( p_image, 1, i_color, 8 );
+ }
+ else
+ {
+ i_processed++;
+ if( bs_read( s, 1 ) == 0x00 ) // Switch1
+ {
+ if( bs_show( s, 7 ) != 0x00 )
+ {
+ i_count = bs_read( s, 7 );
+ (*p) += i_count ;
+ add_rle_code( p_image, i_count, 0x00, 8 );
+ }
+ else
+ {
+ bs_skip( s, 7 );
+ b_stop = 1;
+ }
+ i_processed += 7;
+ }
+ else
+ {
+ i_count = bs_read( s, 7 );
+ (*p) += i_count ;
+ i_color = bs_read( s, 8 );
+ add_rle_code( p_image, i_count, i_color, 8 );
+ i_processed += 15;
+ }
+ }
}
- free(p_i);
-}
+ bs_align( s );
-static void free_object (dvbsub_object_t* p_o)
-{
- free(p_o);
+ return ( i_processed + 7 ) / 8 ;
}
-static void free_objectdefs ( dvbsub_objectdef_t* p_o)
+static dvbsub_image_t *dup_image( dvbsub_image_t *p_i )
{
- dvbsub_objectdef_t* p1;
- dvbsub_objectdef_t* p2=NULL;
+ dvbsub_image_t *p_image = malloc( sizeof(dvbsub_image_t) );
+ dvbsub_rle_t *p_rle = p_i->p_codes;
+
+ *p_image = *p_i;
+ p_image->p_last = NULL;
- for( p1 = p_o; p1 != NULL; p1=p2)
+ while( p_rle )
{
- p2=p1->p_next;
- free(p1);
- p1=NULL;
+ dvbsub_rle_t *p_last = p_image->p_last;
+ p_image->p_last = malloc( sizeof(dvbsub_rle_t) );
+ if( !p_last ) p_image->p_codes = p_image->p_last;
+ if( p_last ) p_last->p_next = p_image->p_last;
+ *p_image->p_last = *p_rle;
+ p_rle = p_rle->p_next;
}
+
+ return p_image;
}
-static void free_regions (dvbsub_region_t* p_r, uint8_t nb)
+static void free_image( dvbsub_image_t *p_i )
{
- unsigned int i;
+ dvbsub_rle_t *p1;
+ dvbsub_rle_t *p2 = NULL;
- for (i = 0; i<nb; i++) free_objectdefs ( p_r[i].p_object );
- free (p_r);
- p_r = NULL;
+ for( p1 = p_i->p_codes; p1 != NULL; p1 = p2 )
+ {
+ p2 = p1->p_next;
+ free( p1 );
+ p1 = NULL;
+ }
+
+ free( p_i );
}
-static void free_objects (dvbsub_object_t* p_o)
+static void free_spu( subpicture_t *p_spu )
{
- dvbsub_object_t* p1;
- dvbsub_object_t* p2=NULL;
+ dvbsub_render_t *p_obj, *p_obj_next;
- for( p1 = p_o; p1 != NULL; p1=p2)
+ for( p_obj = p_spu->p_sys->p_objects; p_obj != NULL; p_obj = p_obj_next )
{
- p2=p1->p_next;
- free_image (p1->topfield);
- free_image (p1->bottomfield);
- free_object(p1);
+ p_obj_next = p_obj->p_next;
+ free_image( p_obj->p_rle_top );
+ free_image( p_obj->p_rle_bot );
+ free( p_obj );
}
+ free( p_spu->p_sys );
+ p_spu->p_sys = NULL;
}
-static void free_clut ( dvbsub_clut_t* p_c )
+static void free_objects( decoder_t *p_dec )
{
- free(p_c);
-}
+ decoder_sys_t *p_sys = p_dec->p_sys;
+ dvbsub_object_t *p_obj, *p_obj_next;
-static void free_page (dvbsub_page_t* p_p)
-{
- free_regions (p_p->regions, p_p->i_regions_number);
- free(p_p);
- p_p = NULL;
+ for( p_obj = p_sys->p_objects; p_obj != NULL; p_obj = p_obj_next )
+ {
+ p_obj_next = p_obj->p_next;
+ free_image( p_obj->topfield );
+ free_image( p_obj->bottomfield );
+ free( p_obj );
+ }
+ p_sys->p_objects = NULL;
}
-static void free_spu( subpicture_t *p_spu )
+static void free_all( decoder_t *p_dec )
{
- if ( p_spu->p_sys )
+ decoder_sys_t *p_sys = p_dec->p_sys;
+ dvbsub_region_t *p_reg, *p_reg_next;
+ int i;
+
+ for( i = 0; i < 256; i++ )
{
- free_image(((dvbsub_render_t *)p_spu->p_sys->p_data)->p_rle_top);
- free_image(((dvbsub_render_t *)p_spu->p_sys->p_data)->p_rle_bot);
- free(p_spu->p_sys->p_data);
- free( p_spu->p_sys );
- p_spu->p_sys = NULL;
+ if( p_sys->p_clut[i] ) free( p_sys->p_clut[i] );
+ p_sys->p_clut[i] = NULL;
}
-}
-static void free_all ( dvbsub_all_t* p_a )
-{
- unsigned int i;
+ if( p_sys->p_page )
+ {
+ if( p_sys->p_page->i_region_defs )
+ free( p_sys->p_page->p_region_defs );
+ free( p_sys->p_page );
+ p_sys->p_page = NULL;
+ }
- for(i=0; i<0xff; i++) if (p_a->p_clut[i]) free_clut ( p_a->p_clut[i] );
- for(i=0; i<16; i++) if (p_a->p_spu[i]) free_spu ( p_a->p_spu[i] );
- if(p_a->p_page) free_page( p_a->p_page );
- free_objects (p_a->p_objects);
+ for( p_reg = p_sys->p_regions; p_reg != NULL; p_reg = p_reg_next )
+ {
+ p_reg_next = p_reg->p_next;
+ if( p_reg->i_object_defs ) free( p_reg->p_object_defs );
+ free( p_reg );
+ }
+ p_sys->p_regions = NULL;
+
+ free_objects( p_dec );
}
static void RenderYUY2( vout_thread_t *p_vout, picture_t *p_pic,
- const subpicture_t *p_spu )
+ dvbsub_render_t *p_r )
{
/* Common variables */
uint8_t *p_desty;
uint16_t i_cnt;
uint16_t x, y;
dvbsub_rle_t* p_c;
- dvbsub_render_t* p_r = ((dvbsub_render_t *)p_spu->p_sys->p_data);
dvbsub_image_t* p_im = p_r->p_rle_top;
i=0;
j=0;
}
static void RenderI42x( vout_thread_t *p_vout, picture_t *p_pic,
- const subpicture_t *p_spu )
+ dvbsub_render_t *p_r )
{
/* Common variables */
- uint8_t *p_desty;
- uint8_t *p_destu;
- uint8_t *p_destv;
- uint16_t i,j;
- uint16_t x, y;
- dvbsub_rle_t* p_c;
- dvbsub_render_t* p_r = ((dvbsub_render_t *)p_spu->p_sys->p_data);
+ uint8_t *p_desty = p_pic->Y_PIXELS;
+ uint8_t *p_destu = p_pic->U_PIXELS;
+ uint8_t *p_destv = p_pic->V_PIXELS;
dvbsub_image_t* p_im = p_r->p_rle_top;
- i=0;
- j=0;
- p_desty = p_pic->Y_PIXELS;
- p_destu = p_pic->U_PIXELS;
- p_destv = p_pic->V_PIXELS;
- //let's render the 1st frame
- for(p_c = p_im->p_codes; p_c->p_next != NULL; p_c=p_c->p_next)
+ dvbsub_rle_t* p_c;
+ uint16_t i, j, x, y;
+ int i_x_subsampling =
+ p_vout->output.i_chroma == VLC_FOURCC('I','4','2','2') ? 1 : 2;
+
+ /* Let's render the top field */
+ p_im = p_r->p_rle_bot; i = 0; j = 0;
+ for( p_c = p_im->p_codes; p_c->p_next != NULL; p_c = p_c->p_next )
{
- if( p_c->y != 0 )
+ if( p_c->y != 0 && p_c->t != 0xFF )
{
- x = j+ p_r->i_x;
- y = 2*i+p_r->i_y;
- //memset(p_dest+ y*p_pic->U_PITCH*2 + x, p_c->cr, p_c->i_num);
- //memset(p_desty+ (y)*p_pic->Y_PITCH + x, p_c->cr, p_c->i_num);
- //memset(p_dest+ y*p_pic->V_PITCH*2 + x, p_c->cb, p_c->i_num);
- //memset(p_destu+ (y)*p_pic->Y_PITCH + x, p_c->cb, p_c->i_num);
- memset(p_desty+ y*p_pic->Y_PITCH + x, p_c->y, p_c->i_num);
- //memset(p_desty+ 2*y*p_pic->U_PITCH + x, p_c->cr, p_c->i_num);
- //memset(p_desty+ 2*y*p_pic->V_PITCH + x, p_c->cb, p_c->i_num);
+ x = j + p_r->i_x;
+ y = 2 * i + p_r->i_y;
+ memset( p_desty + y * p_pic->Y_PITCH + x, p_c->y, p_c->i_num );
+
+ memset( p_destu + y/2 * p_pic->U_PITCH + x/i_x_subsampling,
+ p_c->cr, p_c->i_num/i_x_subsampling );
+ memset( p_destv + y/2 * p_pic->V_PITCH + x/i_x_subsampling,
+ p_c->cb, p_c->i_num/i_x_subsampling );
}
+
j += p_c->i_num;
- if(j >= p_im->i_cols[i])
+ if( j >= p_im->i_cols[i] )
{
i++; j=0;
}
- if( i>= p_im->i_rows) break;
+
+ if( i >= p_im->i_rows) break;
}
- //idem for the second frame
- p_im = p_r->p_rle_bot; i=0; j=0;
- for(p_c = p_im->p_codes; p_c->p_next != NULL; p_c=p_c->p_next)
+
+ /* Idem for the bottom field */
+ p_im = p_r->p_rle_bot; i = 0; j = 0;
+ for( p_c = p_im->p_codes; p_c->p_next != NULL; p_c = p_c->p_next )
{
- if( p_c->y != 0 && p_c->t < 0x20)
+ if( p_c->y != 0 && p_c->t != 0xFF )
{
- x = j+ p_r->i_x;
- y = 2*i+1+p_r->i_y;
- //memset(p_desty+ y*p_pic->U_PITCH*2 + x, p_c->cr, p_c->i_num);
- //memset(p_desty+ y*p_pic->V_PITCH*2 + x, p_c->cb, p_c->i_num);
+ x = j + p_r->i_x;
+ y = 2*i + 1 + p_r->i_y;
+
memset(p_desty+ y*p_pic->Y_PITCH + x, p_c->y, p_c->i_num);
- //memset(p_desty+ 2*y*p_pic->U_PITCH + x, p_c->cr, p_c->i_num);
- //memset(p_desty+ 2*y*p_pic->V_PITCH + x, p_c->cb, p_c->i_num);
+
+ /* No U or V (decimation) */
}
+
j += p_c->i_num;
- if(j >= p_im->i_cols[i])
+ if( j >= p_im->i_cols[i] )
{
i++; j=0;
}
- if( i>= p_im->i_rows) break;
+
+ if( i >= p_im->i_rows ) break;
}
}
static void RenderDVBSUB( vout_thread_t *p_vout, picture_t *p_pic,
const subpicture_t *p_spu )
{
- /* If we have changed the language on the fly */
+ dvbsub_render_t* p_render;
- if( p_spu->p_sys == NULL || p_spu->p_sys->b_obsolete )
- {
- return;
- }
+ if( p_spu->p_sys == NULL ) return;
- switch( p_vout->output.i_chroma )
+ p_render = p_spu->p_sys->p_objects;
+ while( p_render )
{
+
+ switch( p_vout->output.i_chroma )
+ {
/* I420 target, no scaling */
case VLC_FOURCC('I','4','2','2'):
case VLC_FOURCC('I','4','2','0'):
/* As long as we just use Y info, I422 and YV12 are just equivalent
* to I420. Remember to change it the day we'll take into account
* U and V info. */
- RenderI42x( p_vout, p_pic, p_spu );
+ RenderI42x( p_vout, p_pic, p_render );
break;
/* RV16 target, scaling */
/* NVidia overlay, no scaling */
case VLC_FOURCC('Y','U','Y','2'):
- RenderYUY2( p_vout, p_pic, p_spu );
+ RenderYUY2( p_vout, p_pic, p_render );
break;
default:
msg_Err( p_vout, "unknown chroma, can't render SPU" );
break;
+ }
+
+ p_render = p_render->p_next;
}
}
-static void dvbsub_Destroy( subpicture_t *p_spu )
+static void render( decoder_t *p_dec, vout_thread_t *p_vout )
{
- free_spu( p_spu );
-}
+ decoder_sys_t *p_sys = p_dec->p_sys;
+ dvbsub_render_t *p_render = NULL, *p_current, *p_last = NULL;
+ dvbsub_clut_t *p_clut;
+ dvbsub_rle_t *p_c;
+ int i, j = 0, i_timeout = 0;
-static void render( dvbsub_all_t *dvbsub, vout_thread_t *p_vout )
-{
- dvbsub_region_t* p_region;
- dvbsub_objectdef_t* p_objectdef;
- dvbsub_object_t* p_o;
- dvbsub_object_t* p_object;
- dvbsub_object_t* p_object_old;
- dvbsub_render_t* p_render;
- dvbsub_rle_t* p_c;
- uint8_t i , j = 0;
-
- /* loop on regions */
- for( i = 0; i < dvbsub->p_page->i_regions_number; i++ )
+ /* Allocate the subpicture internal data. */
+#ifdef DEBUG_DVBSUB
+ if( !p_vout ) p_sys->p_spu = malloc( sizeof(subpicture_t) );
+ else
+#endif
+ p_sys->p_spu =
+ vout_CreateSubPicture( p_vout, p_sys->i_subpic_channel,
+ MEMORY_SUBPICTURE );
+ if( p_sys->p_spu == NULL ) return;
+
+ /* Loop on region definitions */
+#ifdef DEBUG_DVBSUB
+ if( p_sys->p_page )
+ msg_Dbg( p_dec, "rendering %i regions", p_sys->p_page->i_region_defs );
+#endif
+
+ for( i = 0; p_sys->p_page && i < p_sys->p_page->i_region_defs; i++ )
{
- p_region = &(dvbsub->p_page->regions[i]);
+ dvbsub_region_t *p_region;
+ dvbsub_regiondef_t *p_regiondef;
+
+ i_timeout = p_sys->p_page->i_timeout;
+
+ p_regiondef = &p_sys->p_page->p_region_defs[i];
+
+#ifdef DEBUG_DVBSUB
+ msg_Dbg( p_dec, "rendering region %i (%i,%i)", i,
+ p_regiondef->i_x, p_regiondef->i_y );
+#endif
+
+ /* Find associated region */
+ for( p_region = p_sys->p_regions; p_region != NULL;
+ p_region = p_region->p_next )
+ {
+ if( p_regiondef->i_id == p_region->i_id ) break;
+ }
+
+ if( !p_region )
+ {
+ msg_Err( p_dec, "no region founddddd!!!" );
+ continue;
+ }
- /* loop on objects */
- for( p_objectdef = p_region->p_object; p_objectdef != NULL;
- p_objectdef = p_objectdef->p_next )
+ /* Loop on object definitions */
+ for( j = 0; j < p_region->i_object_defs; j++ )
{
+ dvbsub_object_t *p_object;
+ dvbsub_objectdef_t *p_objectdef;
+
+ p_objectdef = &p_region->p_object_defs[j];
+
+#ifdef DEBUG_DVBSUB
+ msg_Dbg( p_dec, "rendering object %i (%i,%i)", p_objectdef->i_id,
+ p_objectdef->i_x, p_objectdef->i_y );
+#endif
+
/* Look for the right object */
- p_object = dvbsub->p_objects;
- while( !p_object && p_object->i_id != p_objectdef->i_id )
+ for( p_object = p_sys->p_objects; p_object != NULL;
+ p_object = p_object->p_next )
{
- p_object = p_object->p_next;
+ if( p_objectdef->i_id == p_object->i_id ) break;
}
if( !p_object )
{
- msg_Err( p_vout, "internal decoder error");
- return;
+ msg_Err( p_dec, "no object founddddd!!!" );
+ continue;
}
/* Allocate the render structure */
- p_render = malloc( sizeof(dvbsub_render_t) );
- p_render->i_x = p_region->i_x + p_objectdef->i_xoffset;
- p_render->i_y = p_region->i_y + p_objectdef->i_yoffset;
- p_render->p_rle_top = p_object->topfield;
- p_render->p_rle_bot = p_object->bottomfield;
+ p_current = malloc( sizeof(dvbsub_render_t) );
+ p_current->p_next = NULL;
+ p_current->i_x = p_regiondef->i_x + p_objectdef->i_x;
+ p_current->i_y = p_regiondef->i_y + p_objectdef->i_y;
+ p_current->p_rle_top = dup_image( p_object->topfield );
+ p_current->p_rle_bot = dup_image( p_object->bottomfield );
- // if we did not recieved the CLUT yet
- if( !dvbsub->p_clut[p_region->i_clut] ) return;
+ if( !p_render ) p_render = p_current;
+ if( p_last ) p_last->p_next = p_current;
+ p_last = p_current;
+
+ p_clut = p_sys->p_clut[p_region->i_clut];
+ if( !p_clut ) p_clut = &p_sys->default_clut;
/* Compute the color datas according to the appropriate CLUT */
- for( p_c = p_render->p_rle_top->p_codes;
+ for( p_c = p_current->p_rle_top->p_codes;
p_c->p_next != NULL; p_c = p_c->p_next )
{
- //TODO We assume here we are working in 4bp
- p_c->y = dvbsub->p_clut[p_region->i_clut]->c_4b[p_c->i_color_code].Y;
- p_c->cr = dvbsub->p_clut[p_region->i_clut]->c_4b[p_c->i_color_code].Cr;
- p_c->cb = dvbsub->p_clut[p_region->i_clut]->c_4b[p_c->i_color_code].Cb;
- p_c->t = dvbsub->p_clut[p_region->i_clut]->c_4b[p_c->i_color_code].T;
+ dvbsub_color_t *p_color = (p_c->i_bpp == 2) ? p_clut->c_2b :
+ (p_c->i_bpp == 4) ? p_clut->c_4b : p_clut->c_8b;
+
+ p_c->y = p_color[p_c->i_color_code].Y;
+ p_c->cr = p_color[p_c->i_color_code].Cr;
+ p_c->cb = p_color[p_c->i_color_code].Cb;
+ p_c->t = p_color[p_c->i_color_code].T;
}
- for( p_c = p_render->p_rle_bot->p_codes; p_c->p_next != NULL;
+ for( p_c = p_current->p_rle_bot->p_codes; p_c->p_next != NULL;
p_c = p_c->p_next )
{
- //TODO We assume here we are working in 4bp
- p_c->y = dvbsub->p_clut[p_region->i_clut]->c_4b[p_c->i_color_code].Y;
- p_c->cr = dvbsub->p_clut[p_region->i_clut]->c_4b[p_c->i_color_code].Cr;
- p_c->cb = dvbsub->p_clut[p_region->i_clut]->c_4b[p_c->i_color_code].Cb;
- p_c->t = dvbsub->p_clut[p_region->i_clut]->c_4b[p_c->i_color_code].T;
- }
+ dvbsub_color_t *p_color = (p_c->i_bpp == 2) ? p_clut->c_2b :
+ (p_c->i_bpp == 4) ? p_clut->c_4b : p_clut->c_8b;
-
- /* Allocate the subpicture internal data. */
- dvbsub->p_spu[j] =
- vout_CreateSubPicture( p_vout, dvbsub->i_subpic_channel,
- MEMORY_SUBPICTURE );
- if( dvbsub->p_spu[j] == NULL )
- {
- msg_Err(p_vout, "Unable to allocate memory, skipping");
- return;
- }
- /* Set the pf_render callback */
- dvbsub->p_spu[j]->pf_render = RenderDVBSUB;
- dvbsub->p_spu[j]->p_sys = malloc( sizeof(subpicture_sys_t) );
- dvbsub->p_spu[j]->p_sys->p_data = p_render;
- dvbsub->p_spu[j]->p_sys->b_obsolete = 0;
- dvbsub->p_spu[j]->pf_destroy = dvbsub_Destroy;
- dvbsub->p_spu[j]->i_start = dvbsub->i_pts;
- dvbsub->p_spu[j]->i_stop = dvbsub->p_spu[j]->i_start +
- dvbsub->p_page->i_timeout * 1000000;
- dvbsub->p_spu[j]->b_ephemer = VLC_FALSE;
-
- // At this stage, we have all we need in p_render
- // We need to free the object
- //Remove this object from the list
- p_object_old = p_object;
- if( p_object == dvbsub->p_objects )
- {
- dvbsub->p_objects = p_object->p_next;
- }
- else
- {
- for( p_o = dvbsub->p_objects; p_o->p_next != p_object;
- p_o = p_o->p_next );
- p_o->p_next = p_object->p_next;
+ p_c->y = p_color[p_c->i_color_code].Y;
+ p_c->cr = p_color[p_c->i_color_code].Cr;
+ p_c->cb = p_color[p_c->i_color_code].Cb;
+ p_c->t = p_color[p_c->i_color_code].T;
}
- free_object(p_object_old);
+ }
+ }
- vout_DisplaySubPicture( p_vout, dvbsub->p_spu[j] );
+ /* Set the pf_render callback */
+ p_sys->p_spu->pf_render = RenderDVBSUB;
+ p_sys->p_spu->p_sys = malloc( sizeof(subpicture_sys_t) );
+ p_sys->p_spu->p_sys->p_objects = p_render;
+ p_sys->p_spu->pf_destroy = free_spu;
+ p_sys->p_spu->i_start = p_sys->i_pts;
+ p_sys->p_spu->i_stop = p_sys->p_spu->i_start + i_timeout * 1000000;
+ p_sys->p_spu->b_ephemer = VLC_TRUE;
- j++;
- }
+#ifdef DEBUG_DVBSUB
+ if( !p_vout )
+ {
+ free_spu( p_sys->p_spu );
+ free( p_sys->p_spu );
+ p_sys->p_spu = NULL;
+ return;
}
+#endif
+
+ vout_DisplaySubPicture( p_vout, p_sys->p_spu );
}