Commit c523f5a5 authored by Gildas Bazin's avatar Gildas Bazin

* modules/codec/dvbsub.c: rewrite of the DVB subtitles decoder.

   It can finally decode properly all the samples I have.
parent 859483c8
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
* *
* Authors: Damien LUCAS <damien.lucas@anevia.com> * Authors: Damien LUCAS <damien.lucas@anevia.com>
* Laurent Aimar <fenrir@via.ecp.fr> * Laurent Aimar <fenrir@via.ecp.fr>
* Gildas Bazin <gbazin@videolan.org>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
...@@ -31,6 +32,8 @@ ...@@ -31,6 +32,8 @@
#include "vlc_bits.h" #include "vlc_bits.h"
//#define DEBUG_DVBSUB 1
/***************************************************************************** /*****************************************************************************
* Module descriptor. * Module descriptor.
*****************************************************************************/ *****************************************************************************/
...@@ -52,45 +55,67 @@ vlc_module_end(); ...@@ -52,45 +55,67 @@ vlc_module_end();
/* Storage of a RLE entry */ /* Storage of a RLE entry */
typedef struct dvbsub_rle_s typedef struct dvbsub_rle_s
{ {
uint16_t i_num; uint16_t i_num;
uint8_t i_color_code; int i_color_code;
int i_bpp;
uint8_t y; uint8_t y;
uint8_t cr; uint8_t cr;
uint8_t cb; uint8_t cb;
uint8_t t; uint8_t t;
struct dvbsub_rle_s* p_next; struct dvbsub_rle_s *p_next;
} dvbsub_rle_t; } dvbsub_rle_t;
/* A subpicture image is a list of codes /* A subpicture image is a list of codes
* We need to store the length of each line since nothing specify in * 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 */ * WARNING: We assume here that a spu is less than 576 lines high */
typedef struct typedef struct
{ {
uint16_t i_rows; uint16_t i_rows;
uint16_t i_cols[576]; uint16_t i_cols[576];
dvbsub_rle_t* p_last; dvbsub_rle_t *p_last;
dvbsub_rle_t* p_codes; dvbsub_rle_t *p_codes;
} dvbsub_image_t; } dvbsub_image_t;
/* The object definition gives the position of the object in a region */ /* The object definition gives the position of the object in a region */
typedef struct dvbsub_objectdef_s typedef struct dvbsub_objectdef_s
{ {
uint16_t i_id; uint16_t i_id;
uint8_t i_type; uint8_t i_type;
uint8_t i_provider; uint8_t i_provider;
uint16_t i_xoffset; uint16_t i_x;
uint16_t i_yoffset; uint16_t i_y;
uint8_t i_fg_pc; uint8_t i_fg_pc;
uint8_t i_bg_pc; uint8_t i_bg_pc;
struct dvbsub_objectdef_s* p_next;
} dvbsub_objectdef_t; } 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 /* The Region is an aera on the image
* with a list of the object definitions associated * with a list of the object definitions associated and a CLUT */
* and a CLUT */
typedef struct dvbsub_region_s typedef struct dvbsub_region_s
{ {
uint8_t i_id; uint8_t i_id;
...@@ -106,7 +131,11 @@ typedef struct dvbsub_region_s ...@@ -106,7 +131,11 @@ typedef struct dvbsub_region_s
uint8_t i_8bp_code; uint8_t i_8bp_code;
uint8_t i_4bp_code; uint8_t i_4bp_code;
uint8_t i_2bp_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; } dvbsub_region_t;
...@@ -117,23 +146,11 @@ typedef struct ...@@ -117,23 +146,11 @@ typedef struct
uint8_t i_timeout; uint8_t i_timeout;
uint8_t i_state; uint8_t i_state;
uint8_t i_version_number; uint8_t i_version_number;
uint8_t i_regions_number;
dvbsub_region_t* regions;
} dvbsub_page_t; uint8_t i_region_defs;
dvbsub_regiondef_t *p_region_defs;
/* 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; } dvbsub_page_t;
/* The entry in the palette CLUT */ /* The entry in the palette CLUT */
typedef struct typedef struct
...@@ -150,50 +167,49 @@ typedef struct ...@@ -150,50 +167,49 @@ typedef struct
{ {
uint8_t i_id; uint8_t i_id;
uint8_t i_version_number; uint8_t i_version_number;
dvbsub_color_t c_2b[0xff]; dvbsub_color_t c_2b[4];
dvbsub_color_t c_4b[0xff]; dvbsub_color_t c_4b[16];
dvbsub_color_t c_8b[0xff]; dvbsub_color_t c_8b[256];
} dvbsub_clut_t; } dvbsub_clut_t;
typedef struct typedef struct dvbsub_render_s
{
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
{ {
int i_id; uint16_t i_x;
uint16_t i_y;
mtime_t i_pts; dvbsub_image_t *p_rle_top;
dvbsub_image_t *p_rle_bot;
dvbsub_clut_t* p_clut[0xff]; struct dvbsub_render_s *p_next;
dvbsub_page_t* p_page;
dvbsub_object_t* p_objects;
subpicture_t* p_spu[16];
int i_subpic_channel;
} dvbsub_all_t; } dvbsub_render_t;
struct subpicture_sys_t struct subpicture_sys_t
{ {
mtime_t i_pts; dvbsub_render_t *p_objects; /* Linked list of objects to render */
void * p_data; /* rle datas are stored */
vlc_object_t* p_input; /* Link to the input */
vlc_bool_t b_obsolete;
}; };
struct decoder_sys_t 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;
}; };
...@@ -219,18 +235,27 @@ struct decoder_sys_t ...@@ -219,18 +235,27 @@ struct decoder_sys_t
#define DVBSUB_DT_28_TABLE_DATA 0x21 #define DVBSUB_DT_28_TABLE_DATA 0x21
#define DVBSUB_DT_48_TABLE_DATA 0x22 #define DVBSUB_DT_48_TABLE_DATA 0x22
#define DVBSUB_DT_END_LINE 0xf0 #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 * 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 render( decoder_t *, vout_thread_t * );
static void decode_segment( decoder_t *, dvbsub_all_t *, bs_t * ); static void default_clut_init( decoder_t * );
static void render( dvbsub_all_t *, vout_thread_t * );
static void dvbsub( dvbsub_all_t * );
/***************************************************************************** /*****************************************************************************
* Open: probe the decoder and return score * Open: probe the decoder and return score
...@@ -240,8 +265,9 @@ static void dvbsub( dvbsub_all_t * ); ...@@ -240,8 +265,9 @@ static void dvbsub( dvbsub_all_t * );
*****************************************************************************/ *****************************************************************************/
static int Open( vlc_object_t *p_this ) 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; decoder_sys_t *p_sys;
int i;
if( p_dec->fmt_in.i_codec != VLC_FOURCC('d','v','b','s') ) if( p_dec->fmt_in.i_codec != VLC_FOURCC('d','v','b','s') )
{ {
...@@ -251,12 +277,20 @@ static int Open( vlc_object_t *p_this ) ...@@ -251,12 +277,20 @@ static int Open( vlc_object_t *p_this )
p_dec->pf_decode_sub = Decode; p_dec->pf_decode_sub = Decode;
p_sys = p_dec->p_sys = malloc( sizeof(decoder_sys_t) ); p_sys = p_dec->p_sys = malloc( sizeof(decoder_sys_t) );
p_sys->p_vout = NULL; p_sys->i_pts = 0;
p_sys->i_id = p_dec->fmt_in.subs.dvb.i_id & 0xFFFF;
init( &p_sys->dvbsub, p_dec->fmt_in.subs.dvb.i_id ); 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' ) ); es_format_Init( &p_dec->fmt_out, SPU_ES, VLC_FOURCC( 'd','v','b','s' ) );
default_clut_init( p_dec );
return VLC_SUCCESS; return VLC_SUCCESS;
} }
...@@ -270,7 +304,7 @@ static void Close( vlc_object_t *p_this ) ...@@ -270,7 +304,7 @@ static void Close( vlc_object_t *p_this )
if( p_sys->p_vout && p_sys->p_vout->p_subpicture != NULL ) if( p_sys->p_vout && p_sys->p_vout->p_subpicture != NULL )
{ {
subpicture_t * p_subpic; subpicture_t *p_subpic;
int i_subpic; int i_subpic;
for( i_subpic = 0; i_subpic < VOUT_MAX_SUBPICTURES; i_subpic++ ) for( i_subpic = 0; i_subpic < VOUT_MAX_SUBPICTURES; i_subpic++ )
{ {
...@@ -284,8 +318,7 @@ static void Close( vlc_object_t *p_this ) ...@@ -284,8 +318,7 @@ static void Close( vlc_object_t *p_this )
} }
} }
dvbsub( &p_sys->dvbsub ); free_all( p_dec );
free( p_sys ); free( p_sys );
} }
...@@ -305,120 +338,137 @@ static void Decode( decoder_t *p_dec, block_t **pp_block ) ...@@ -305,120 +338,137 @@ static void Decode( decoder_t *p_dec, block_t **pp_block )
p_block = *pp_block; p_block = *pp_block;
*pp_block = NULL; *pp_block = NULL;
p_sys->dvbsub.i_pts = p_block->i_pts; p_sys->i_pts = p_block->i_pts;
if( p_sys->dvbsub.i_pts <= 0 ) if( p_sys->i_pts <= 0 )
{ {
msg_Warn( p_dec, "non dated subtitle" ); msg_Warn( p_dec, "non dated subtitle" );
block_Release( p_block ); block_Release( p_block );
return; return;
} }
p_last_vout = p_sys->p_vout; bs_init( &p_sys->bs, p_block->p_buffer, p_block->i_buffer );
if( ( p_sys->p_vout = FindVout( p_dec ) ) )
if( bs_read( &p_sys->bs, 8 ) != 0x20 ) /* Data identifier */
{ {
int i_data_identifier; msg_Dbg( p_dec, "invalid data identifier" );
int i_subtitle_stream_id; block_Release( p_block );
int i_end_data_marker; 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 ); while( bs_show( &p_sys->bs, 8 ) == 0x0f ) /* Sync byte */
i_subtitle_stream_id = bs_read( &p_sys->bs, 8 ); {
decode_segment( p_dec, &p_sys->bs );
}
for( ;; ) if( bs_read( &p_sys->bs, 8 ) != 0xff ) /* End marker */
{ {
if( bs_show( &p_sys->bs, 8 ) != 0x0f ) msg_Warn( p_dec, "end marker not found (corrupted subtitle ?)" );
{ block_Release( p_block );
break; return;
} }
decode_segment( p_dec, &p_sys->dvbsub, &p_sys->bs );
}
i_end_data_marker = bs_read( &p_sys->bs, 8 );
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 ) 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 ); vout_RegisterOSDChannel( p_sys->p_vout );
} }
/* Check if the page is to be displayed */ /* Check if the page is to be displayed */
if( p_sys->dvbsub.p_page && p_sys->dvbsub.p_objects ) if( p_sys->p_page ) render( p_dec, p_sys->p_vout );
{
render( &p_sys->dvbsub, p_sys->p_vout );
}
vlc_object_release( 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 ); block_Release( p_block );
} }
/* following functions are local */ /* 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( ;; ) decoder_sys_t *p_sys = p_dec->p_sys;
{ uint8_t i;
vout_thread_t *p_vout;
if( p_dec->b_die || p_dec->b_error ) #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;
return NULL; #define RGB_TO_V(r, g, b) ((int16_t) 131 * r - 110 * g - 21 * b) / 256;
}
p_vout = vlc_object_find( p_dec, VLC_OBJECT_VOUT, FIND_ANYWHERE );
if( p_vout )
{
return p_vout;
}
msleep( VOUT_OUTMEM_SLEEP );
}
}
static int init( dvbsub_all_t *p_dvbsub, int i_id ) /* 4 entries CLUT */
{ for( i = 0; i < 4; i++ )
int 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_sys->default_clut.c_2b[i].Y = RGB_TO_Y(R,G,B);
p_dvbsub->i_id = i_id; p_sys->default_clut.c_2b[i].Cr = RGB_TO_U(R,G,B);
p_dvbsub->p_page = NULL; p_sys->default_clut.c_2b[i].Cb = RGB_TO_V(R,G,B);
p_dvbsub->p_objects = NULL; p_sys->default_clut.c_2b[i].T = T;
for( i = 0; i < 255; i++ )
{
p_dvbsub->p_clut[i] = NULL;
} }
/* 16 entries CLUT */
for( i = 0; i < 16; i++ ) for( i = 0; i < 16; i++ )
{ {
p_dvbsub->p_spu[i] = NULL; uint8_t R = 0, G = 0, B = 0, T = 0;
}
return 0;
}
static void free_all( dvbsub_all_t * );
static void dvbsub( dvbsub_all_t *p_dvbsub ) if( !(i & 0x8) )
{ {
free_all( p_dvbsub ); 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 ); p_sys->default_clut.c_4b[i].Y = RGB_TO_Y(R,G,B);
static void decode_page_composition( dvbsub_all_t *p_dvbsub, bs_t *s); p_sys->default_clut.c_4b[i].Cr = RGB_TO_U(R,G,B);
static void decode_region_composition( dvbsub_all_t *p_dvbsub, bs_t *s ); p_sys->default_clut.c_4b[i].Cb = RGB_TO_V(R,G,B);
static void stop_display( dvbsub_all_t* p_dvbsub ); p_sys->default_clut.c_4b[i].T = T;
static void decode_object( dvbsub_all_t *p_dvbsub, bs_t *s ); }
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_type;
int i_page_id; int i_page_id;
int i_size; int i_size;
/* sync_byte */ /* sync_byte (already checked) */
bs_skip( s, 8 ); bs_skip( s, 8 );
/* segment type */ /* segment type */
...@@ -430,45 +480,66 @@ static void decode_segment( decoder_t *p_dec, dvbsub_all_t *p_dvbspu, bs_t *s ) ...@@ -430,45 +480,66 @@ static void decode_segment( decoder_t *p_dec, dvbsub_all_t *p_dvbspu, bs_t *s )
/* segment size */ /* segment size */
i_size = bs_show( s, 16 ); 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 ) ); bs_skip( s, 8 * ( 2 + i_size ) );
return; 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 ) switch( i_type )
{ {
case DVBSUB_ST_CLUT_DEFINITION: case DVBSUB_ST_PAGE_COMPOSITION:
#ifdef DEBUG_DVBSUB #ifdef DEBUG_DVBSUB
msg_Dbg( p_dec, "subtitle dvbsub_decode_clut" ); msg_Dbg( p_dec, "decode_page_composition" );
#endif #endif
decode_clut( p_dvbspu, s ); decode_page_composition( p_dec, s );
break; break;
case DVBSUB_ST_PAGE_COMPOSITION:
case DVBSUB_ST_REGION_COMPOSITION:
#ifdef DEBUG_DVBSUB #ifdef DEBUG_DVBSUB
msg_Dbg( p_dec, "subtitle dvbsub_decode_page_composition" ); msg_Dbg( p_dec, "decode_region_composition" );
#endif #endif
decode_page_composition( p_dvbspu, s ); decode_region_composition( p_dec, s );
break; break;
case DVBSUB_ST_REGION_COMPOSITION:
case DVBSUB_ST_CLUT_DEFINITION:
#ifdef DEBUG_DVBSUB #ifdef DEBUG_DVBSUB
msg_Dbg( p_dec, "subtitle dvbsub_decode_region_composition" ); msg_Dbg( p_dec, "decode_clut" );
#endif #endif
decode_region_composition( p_dvbspu, s ); decode_clut( p_dec, s );
break; break;
case DVBSUB_ST_OBJECT_DATA: case DVBSUB_ST_OBJECT_DATA:
#ifdef DEBUG_DVBSUB #ifdef DEBUG_DVBSUB
msg_Dbg( p_dec, "subtitle dvbsub_decode_object" ); msg_Dbg( p_dec, "decode_object" );
#endif #endif
decode_object( p_dvbspu, s ); decode_object( p_dec, s );
break; break;
case DVBSUB_ST_ENDOFDISPLAY: case DVBSUB_ST_ENDOFDISPLAY:
#ifdef DEBUG_DVBSUB #ifdef DEBUG_DVBSUB
msg_Dbg( p_dec, "subtitle dvbsub_stop_display" ); msg_Dbg( p_dec, "end of display" );
#endif #endif
stop_display( p_dvbspu ); bs_skip( s, 8 * ( 2 + i_size ) );
break; break;
case DVBSUB_ST_STUFFING: case DVBSUB_ST_STUFFING:
#ifdef DEBUG_DVBSUB
msg_Dbg( p_dec, "skip stuffing" );
#endif
bs_skip( s, 8 * ( 2 + i_size ) );
break;
default: default:
msg_Warn( p_dec, "unsupported segment type: (%04x)", i_type ); msg_Warn( p_dec, "unsupported segment type: (%04x)", i_type );
bs_skip( s, 8 * ( 2 + i_size ) ); bs_skip( s, 8 * ( 2 + i_size ) );
...@@ -476,51 +547,38 @@ static void decode_segment( decoder_t *p_dec, dvbsub_all_t *p_dvbspu, bs_t *s ) ...@@ -476,51 +547,38 @@ static void decode_segment( decoder_t *p_dec, dvbsub_all_t *p_dvbspu, bs_t *s )
} }
} }
static void stop_display( dvbsub_all_t *p_dvbsub ) static void decode_clut( decoder_t *p_dec, bs_t *s )
{
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 )
{ {
uint16_t i_segment_length; decoder_sys_t *p_sys = p_dec->p_sys;
uint16_t i_processed_length; uint16_t i_segment_length;
dvbsub_clut_t* clut; uint16_t i_processed_length;
uint8_t i_clut_id; dvbsub_clut_t *p_clut;
uint8_t i_version_number; uint8_t i_clut_id;
uint8_t i_version_number;
i_segment_length = bs_read( s, 16 ); i_segment_length = bs_read( s, 16 );
i_clut_id = bs_read( s, 8 ); i_clut_id = bs_read( s, 8 );
i_version_number = bs_read( s, 4 ); i_version_number = bs_read( s, 4 );
// Check that this id doesn't not already exist /* Check that this id doesn't not already exist with the same version
// with the same version number * number and allocate memory if necessary */
// And allocate memory if necessary if( p_sys->p_clut[i_clut_id] != NULL &&
if( p_dvbsub->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 ) /* Nothing to do */
{ bs_skip( s, 8 * i_segment_length - 12 );
//TODO skip the right number of bits return;
return;
}
else
{
memset( p_dvbsub->p_clut[i_clut_id], 0, sizeof(dvbsub_clut_t) );
}
} }
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 */ /* 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 */ bs_skip( s, 4 ); /* Reserved bits */
i_processed_length = 2; i_processed_length = 2;
while( i_processed_length < i_segment_length ) while( i_processed_length < i_segment_length )
...@@ -552,119 +610,162 @@ static void decode_clut( dvbsub_all_t *p_dvbsub, bs_t *s ) ...@@ -552,119 +610,162 @@ static void decode_clut( dvbsub_all_t *p_dvbsub, bs_t *s )
} }
/* According to EN 300-743 section 7.2.3 note 1, type should /* According to EN 300-743 section 7.2.3 note 1, type should
* not have more than 1 bit set to one * not have more than 1 bit set to one, but some strams don't
But, some strams don't respect this note. */ * respect this note. */
if( i_type&0x04) if( i_type&0x04)
{ {
clut->c_2b[i_id].Y = y; p_clut->c_2b[i_id].Y = y;
clut->c_2b[i_id].Cr = cr; p_clut->c_2b[i_id].Cr = cr;
clut->c_2b[i_id].Cb = cb; p_clut->c_2b[i_id].Cb = cb;
clut->c_2b[i_id].T = t; p_clut->c_2b[i_id].T = t;
} }
if( i_type&0x02) if( i_type&0x02)
{ {
clut->c_4b[i_id].Y = y; p_clut->c_4b[i_id].Y = y;
clut->c_4b[i_id].Cr = cr; p_clut->c_4b[i_id].Cr = cr;
clut->c_4b[i_id].Cb = cb; p_clut->c_4b[i_id].Cb = cb;
clut->c_4b[i_id].T = t; p_clut->c_4b[i_id].T = t;
} }
if( i_type & 0x01) if( i_type & 0x01)
{ {
clut->c_8b[i_id].Y = y; p_clut->c_8b[i_id].Y = y;
clut->c_8b[i_id].Cr = cr; p_clut->c_8b[i_id].Cr = cr;
clut->c_8b[i_id].Cb = cb; p_clut->c_8b[i_id].Cb = cb;
clut->c_8b[i_id].T = t; 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_version_number;
unsigned int i_state; unsigned int i_state;
unsigned int i_segment_length; unsigned int i_segment_length;
uint8_t i_timeout; uint8_t i_timeout;
unsigned int i; 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_timeout = bs_read( s, 8 );
i_version_number = bs_read( s, 4 ); i_version_number = bs_read( s, 4 );
i_state = bs_read( s, 2 ); 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 */ bs_skip( s, 2 ); /* Reserved */
/* Allocate a new page */ if( i_state == DVBSUB_PCS_STATE_CHANGE )
p_dvbsub->p_page = malloc( sizeof(dvbsub_page_t) ); {
p_dvbsub->p_page->i_timeout = i_timeout; /* 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: */ /* Check version number */
p_dvbsub->p_page->i_regions_number = (i_segment_length-2) / 6; 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 if( !p_sys->p_page )
* instead of a 0x80 packet (End Of Display) */
if( p_dvbsub->p_page->i_regions_number == 0 )
{ {
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 = p_sys->p_page->i_version_number = i_version_number;
malloc( p_dvbsub->p_page->i_regions_number * sizeof(dvbsub_region_t) ); p_sys->p_page->i_timeout = i_timeout;
for( i = 0; i < p_dvbsub->p_page->i_regions_number; i++ )
/* 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 */ bs_skip( s, 8 ); /* Reserved */
p_dvbsub->p_page->regions[i].i_x = bs_read( s, 16 ); p_sys->p_page->p_region_defs[i].i_x = bs_read( s, 16 );
p_dvbsub->p_page->regions[i].i_y = bs_read( s, 16 ); p_sys->p_page->p_region_defs[i].i_y = bs_read( s, 16 );
p_dvbsub->p_page->regions[i].p_object = NULL;
#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( decoder_t *p_dec, bs_t *s )
static void decode_region_composition( dvbsub_all_t *p_dvbsub, bs_t *s )
{ {
dvbsub_region_t* p_region = NULL; decoder_sys_t *p_sys = p_dec->p_sys;
unsigned int i_segment_length; dvbsub_region_t *p_region, **pp_region = &p_sys->p_regions;
unsigned int i_processed_length; int i_segment_length;
unsigned int i_region_id; int i_processed_length;
unsigned int i; int i_region_id;
int i_version_number;
i_segment_length = bs_read( s, 16 ); i_segment_length = bs_read( s, 16 );
/* Get region id: */
i_region_id = bs_read( s, 8 ); 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 ) pp_region = &p_region->p_next;
{ if( p_region->i_id == i_region_id ) break;
p_region = &(p_dvbsub->p_page->regions[i]);
}
} }
if( p_region == NULL ) /* Check version number */
if( p_region &&
p_region->i_version_number == i_version_number )
{ {
/* TODO bs_skip( s, 8 * (i_segment_length - 1) - 4 );
* The region has never been declared before
* Internal error */
fprintf( stderr, "Decoding of undeclared region N/A\n" );
return; return;
} }
else if( p_region )
{
if( p_region->i_object_defs )
free( p_region->p_object_defs );
}
/* Skip version number and fill flag */ if( !p_region )
if( bs_show( s, 4 ) == p_region->i_version_number )
{ {
fprintf( stderr, "Skipping already known region N/A\n" ); #ifdef DEBUG_DVBSUB
/* TODO Skip the right number of bits */ 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 */ /* 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 ); p_region->b_fill = bs_read( s, 1 );
bs_skip( s, 3 ); /* Reserved */ bs_skip( s, 3 ); /* Reserved */
p_region->i_width = bs_read( s, 16 ); p_region->i_width = bs_read( s, 16 );
...@@ -677,24 +778,29 @@ static void decode_region_composition( dvbsub_all_t *p_dvbsub, bs_t *s ) ...@@ -677,24 +778,29 @@ static void decode_region_composition( dvbsub_all_t *p_dvbsub, bs_t *s )
p_region->i_4bp_code = bs_read( s, 4 ); p_region->i_4bp_code = bs_read( s, 4 );
p_region->i_2bp_code = bs_read( s, 2 ); p_region->i_2bp_code = bs_read( s, 2 );
bs_skip( s, 2 ); /* Reserved */ bs_skip( s, 2 ); /* Reserved */
p_region->p_object_defs = NULL;
p_region->i_object_defs = 0;
/* List of objects in the region: */ /* List of objects in the region */
/* We already skipped 10 bytes */
i_processed_length = 10; i_processed_length = 10;
while( i_processed_length < i_segment_length ) while( i_processed_length < i_segment_length )
{ {
dvbsub_objectdef_t *p_obj;
/* We create a new object */ /* 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 */ /* 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_id = bs_read( s, 16 );
p_obj->i_type = bs_read( s, 2 ); p_obj->i_type = bs_read( s, 2 );
p_obj->i_provider = 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 */ 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; i_processed_length += 6;
...@@ -705,48 +811,67 @@ static void decode_region_composition( dvbsub_all_t *p_dvbsub, bs_t *s ) ...@@ -705,48 +811,67 @@ static void decode_region_composition( dvbsub_all_t *p_dvbsub, bs_t *s )
p_obj->i_bg_pc = bs_read( s, 8 ); p_obj->i_bg_pc = bs_read( s, 8 );
i_processed_length += 2; 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, static dvbsub_image_t *dvbsub_parse_pdata( decoder_t *, bs_t *, uint16_t );
uint16_t length ); static uint16_t dvbsub_pdata2bpp( bs_t *, uint16_t *, dvbsub_image_t * );
static uint16_t dvbsub_count0x11( bs_t *s, uint16_t* p, static uint16_t dvbsub_pdata4bpp( bs_t *, uint16_t *, dvbsub_image_t * );
dvbsub_image_t* p_image); 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; decoder_sys_t *p_sys = p_dec->p_sys;
uint16_t i_segment_length; 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 */ /* Check if we already have this region */
p_obj = malloc( sizeof(dvbsub_object_t) ); for( p_obj = p_sys->p_objects; p_obj != NULL; p_obj = p_obj->p_next )
p_obj->p_next = NULL; {
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 = i_obj_id;
p_obj->i_id = bs_read( s, 16 ); p_obj->i_version_number = i_version_number;
p_obj->i_version_number = bs_read( s, 4 ); p_obj->i_coding_method = i_coding_method;
p_obj->i_coding_method = bs_read( s, 2 ); p_obj->b_non_modify_color = bs_read( s, 1 );
p_obj->b_non_modify_color= bs_read( s, 1 );
bs_skip( s, 1 ); /* Reserved */ bs_skip( s, 1 ); /* Reserved */
if( p_obj->i_coding_method == 0x00 ) if( p_obj->i_coding_method == 0x00 )
...@@ -758,22 +883,17 @@ static void decode_object( dvbsub_all_t *p_dvbsub, bs_t *s ) ...@@ -758,22 +883,17 @@ static void decode_object( dvbsub_all_t *p_dvbsub, bs_t *s )
i_bottomfield_length = bs_read( s, 16 ); i_bottomfield_length = bs_read( s, 16 );
p_obj->topfield = p_obj->topfield =
dvbsub_parse_pdata( p_dvbsub, s, i_topfield_length ); dvbsub_parse_pdata( p_dec, s, i_topfield_length );
p_obj->bottomfield = p_obj->bottomfield =
dvbsub_parse_pdata( p_dvbsub, s, i_bottomfield_length ); dvbsub_parse_pdata( p_dec, s, i_bottomfield_length );
} }
else 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 ) uint16_t length )
{ {
dvbsub_image_t* p_image; dvbsub_image_t* p_image;
...@@ -789,31 +909,29 @@ static dvbsub_image_t* dvbsub_parse_pdata( dvbsub_all_t *p_dvbsub, bs_t *s, ...@@ -789,31 +909,29 @@ static dvbsub_image_t* dvbsub_parse_pdata( dvbsub_all_t *p_dvbsub, bs_t *s,
/* Let's parse it a first time to determine the size of the buffer */ /* Let's parse it a first time to determine the size of the buffer */
while( i_processed_length < length) while( i_processed_length < length)
{ {
i_processed_length++;
switch( bs_read( s, 8 ) ) switch( bs_read( s, 8 ) )
{ {
case 0x10: case 0x10:
fprintf(stderr, "0x10 N/A\n"); i_processed_length +=
dvbsub_pdata2bpp( s, &p_image->i_cols[i_lines], p_image );
break; break;
case 0x11: case 0x11:
i_processed_length += i_processed_length +=
1 + dvbsub_count0x11( s, &(p_image->i_cols[i_lines]), dvbsub_pdata4bpp( s, &p_image->i_cols[i_lines], p_image );
p_image );
break; break;
case 0x12: case 0x12:
fprintf(stderr, "0x12 N/A\n"); i_processed_length +=
dvbsub_pdata8bpp( s, &p_image->i_cols[i_lines], p_image );
break; break;
case 0x20: case 0x20:
fprintf(stderr, "0x20 N/A\n");
break;
case 0x21: case 0x21:
fprintf(stderr, "0x21 N/A\n");
break;
case 0x22: case 0x22:
fprintf(stderr, "0x22 N/A\n"); /* We don't use map tables */
break; break;
case 0xf0: case 0xf0:
i_processed_length++; i_lines++; /* End of line code */
i_lines++;
break; break;
} }
} }
...@@ -830,40 +948,113 @@ static dvbsub_image_t* dvbsub_parse_pdata( dvbsub_all_t *p_dvbsub, bs_t *s, ...@@ -830,40 +948,113 @@ static dvbsub_image_t* dvbsub_parse_pdata( dvbsub_all_t *p_dvbsub, bs_t *s,
return p_image; 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_next = malloc( sizeof(dvbsub_rle_t) );
p->p_last = p->p_last->p_next; p->p_last = p->p_last->p_next;
} }
else 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 = p->p_codes;
} }
p->p_last->i_num = num; p->p_last->i_num = num;
p->p_last->i_color_code = color; p->p_last->i_color_code = color;
p->p_last->i_bpp = i_bpp;
p->p_last->p_next = NULL; 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 ) dvbsub_image_t* p_image )
{ {
uint16_t i_processed=0; uint16_t i_processed = 0;
vlc_bool_t b_stop=0; vlc_bool_t b_stop = 0;
uint16_t i_count = 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 ) if( (i_color = bs_read( s, 4 )) != 0x00 )
{ {
(*p)++; (*p)++;
i_processed+=4; i_processed+=4;
/* 1 pixel of color code '0000' */ /* Add 1 pixel */
add_rle_code( p_image, 1, i_color ); add_rle_code( p_image, 1, i_color, 4 );
} }
else else
{ {
...@@ -873,7 +1064,7 @@ static uint16_t dvbsub_count0x11( bs_t *s, uint16_t* p, ...@@ -873,7 +1064,7 @@ static uint16_t dvbsub_count0x11( bs_t *s, uint16_t* p,
{ {
i_count = 2 + bs_read( s, 3 ); i_count = 2 + bs_read( s, 3 );
(*p) += i_count ; (*p) += i_count ;
add_rle_code( p_image, i_count, 0x00 ); add_rle_code( p_image, i_count, 0x00, 4 );
} }
else else
{ {
...@@ -890,7 +1081,7 @@ static uint16_t dvbsub_count0x11( bs_t *s, uint16_t* p, ...@@ -890,7 +1081,7 @@ static uint16_t dvbsub_count0x11( bs_t *s, uint16_t* p,
i_color = bs_read( s, 4 ); i_color = bs_read( s, 4 );
(*p) += i_count; (*p) += i_count;
i_processed += 12; i_processed += 12;
add_rle_code( p_image, i_count, i_color ); add_rle_code( p_image, i_count, i_color, 4 );
} }
else else
{ {
...@@ -899,26 +1090,26 @@ static uint16_t dvbsub_count0x11( bs_t *s, uint16_t* p, ...@@ -899,26 +1090,26 @@ static uint16_t dvbsub_count0x11( bs_t *s, uint16_t* p,
case 0x0: case 0x0:
(*p)++; (*p)++;
i_processed += 8; i_processed += 8;
add_rle_code( p_image, 1, 0x00 ); add_rle_code( p_image, 1, 0x00, 4 );
break; break;
case 0x1: case 0x1:
(*p)+=2; (*p)+=2;
i_processed += 8; i_processed += 8;
add_rle_code( p_image, 2, 0x00 ); add_rle_code( p_image, 2, 0x00, 4 );
break; break;
case 0x2: case 0x2:
i_count = 9 + bs_read( s, 4 ); i_count = 9 + bs_read( s, 4 );
i_color = bs_read( s, 4 ); i_color = bs_read( s, 4 );
(*p)+= i_count; (*p)+= i_count;
i_processed += 16; i_processed += 16;
add_rle_code( p_image, i_count, i_color ); add_rle_code( p_image, i_count, i_color, 4 );
break; break;
case 0x3: case 0x3:
i_count= 25 + bs_read( s, 8 ); i_count= 25 + bs_read( s, 8 );
i_color = bs_read( s, 4 ); i_color = bs_read( s, 4 );
(*p)+= i_count; (*p)+= i_count;
i_processed += 20; i_processed += 20;
add_rle_code( p_image, i_count, i_color ); add_rle_code( p_image, i_count, i_color, 4 );
break; break;
} }
} }
...@@ -931,98 +1122,157 @@ static uint16_t dvbsub_count0x11( bs_t *s, uint16_t* p, ...@@ -931,98 +1122,157 @@ static uint16_t dvbsub_count0x11( bs_t *s, uint16_t* p,
return ( i_processed + 7 ) / 8 ; 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; uint16_t i_processed = 0;
dvbsub_rle_t* p2=NULL; 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; i_processed += 8;
free(p1); if( (i_color = bs_read( s, 8 )) != 0x00 )
p1=NULL; {
(*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) return ( i_processed + 7 ) / 8 ;
{
free(p_o);
} }
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_image_t *p_image = malloc( sizeof(dvbsub_image_t) );
dvbsub_objectdef_t* p2=NULL; 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; dvbsub_rle_t *p_last = p_image->p_last;
free(p1); p_image->p_last = malloc( sizeof(dvbsub_rle_t) );
p1=NULL; 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 ); for( p1 = p_i->p_codes; p1 != NULL; p1 = p2 )
free (p_r); {
p_r = NULL; 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_render_t *p_obj, *p_obj_next;
dvbsub_object_t* p2=NULL;
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; p_obj_next = p_obj->p_next;
free_image (p1->topfield); free_image( p_obj->p_rle_top );
free_image (p1->bottomfield); free_image( p_obj->p_rle_bot );
free_object(p1); 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) for( p_obj = p_sys->p_objects; p_obj != NULL; p_obj = p_obj_next )
{ {
free_regions (p_p->regions, p_p->i_regions_number); p_obj_next = p_obj->p_next;
free(p_p); free_image( p_obj->topfield );
p_p = NULL; 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); if( p_sys->p_clut[i] ) free( p_sys->p_clut[i] );
free_image(((dvbsub_render_t *)p_spu->p_sys->p_data)->p_rle_bot); p_sys->p_clut[i] = NULL;
free(p_spu->p_sys->p_data);
free( p_spu->p_sys );
p_spu->p_sys = NULL;
} }
}
static void free_all ( dvbsub_all_t* p_a ) if( p_sys->p_page )
{ {
unsigned int i; 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( p_reg = p_sys->p_regions; p_reg != NULL; p_reg = p_reg_next )
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 ); p_reg_next = p_reg->p_next;
free_objects (p_a->p_objects); 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, static void RenderYUY2( vout_thread_t *p_vout, picture_t *p_pic,
const subpicture_t *p_spu ) dvbsub_render_t *p_r )
{ {
/* Common variables */ /* Common variables */
uint8_t *p_desty; uint8_t *p_desty;
...@@ -1030,7 +1280,6 @@ static void RenderYUY2( vout_thread_t *p_vout, picture_t *p_pic, ...@@ -1030,7 +1280,6 @@ static void RenderYUY2( vout_thread_t *p_vout, picture_t *p_pic,
uint16_t i_cnt; uint16_t i_cnt;
uint16_t x, y; uint16_t x, y;
dvbsub_rle_t* p_c; 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; dvbsub_image_t* p_im = p_r->p_rle_top;
i=0; i=0;
j=0; j=0;
...@@ -1088,79 +1337,80 @@ static void RenderYUY2( vout_thread_t *p_vout, picture_t *p_pic, ...@@ -1088,79 +1337,80 @@ static void RenderYUY2( vout_thread_t *p_vout, picture_t *p_pic,
} }
static void RenderI42x( vout_thread_t *p_vout, picture_t *p_pic, static void RenderI42x( vout_thread_t *p_vout, picture_t *p_pic,
const subpicture_t *p_spu ) dvbsub_render_t *p_r )
{ {
/* Common variables */ /* Common variables */
uint8_t *p_desty; uint8_t *p_desty = p_pic->Y_PIXELS;
uint8_t *p_destu; uint8_t *p_destu = p_pic->U_PIXELS;
uint8_t *p_destv; uint8_t *p_destv = p_pic->V_PIXELS;
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);
dvbsub_image_t* p_im = p_r->p_rle_top; dvbsub_image_t* p_im = p_r->p_rle_top;
i=0; dvbsub_rle_t* p_c;
j=0; uint16_t i, j, x, y;
p_desty = p_pic->Y_PIXELS; int i_x_subsampling =
p_destu = p_pic->U_PIXELS; p_vout->output.i_chroma == VLC_FOURCC('I','4','2','2') ? 1 : 2;
p_destv = p_pic->V_PIXELS;
//let's render the 1st frame /* Let's render the top field */
for(p_c = p_im->p_codes; p_c->p_next != NULL; p_c=p_c->p_next) 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; x = j + p_r->i_x;
y = 2*i+p_r->i_y; 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->y, 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/2 * p_pic->U_PITCH + x/i_x_subsampling,
//memset(p_destu+ (y)*p_pic->Y_PITCH + x, p_c->cb, p_c->i_num); p_c->cr, p_c->i_num/i_x_subsampling );
memset(p_desty+ y*p_pic->Y_PITCH + x, p_c->y, p_c->i_num); memset( p_destv + y/2 * p_pic->V_PITCH + x/i_x_subsampling,
//memset(p_desty+ 2*y*p_pic->U_PITCH + x, p_c->cr, p_c->i_num); p_c->cb, p_c->i_num/i_x_subsampling );
//memset(p_desty+ 2*y*p_pic->V_PITCH + x, p_c->cb, p_c->i_num);
} }
j += p_c->i_num; j += p_c->i_num;
if(j >= p_im->i_cols[i]) if( j >= p_im->i_cols[i] )
{ {
i++; j=0; 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; /* Idem for the bottom field */
for(p_c = p_im->p_codes; p_c->p_next != NULL; p_c=p_c->p_next) 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; x = j + p_r->i_x;
y = 2*i+1+p_r->i_y; 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);
memset(p_desty+ y*p_pic->Y_PITCH + x, p_c->y, 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); /* No U or V (decimation) */
} }
j += p_c->i_num; j += p_c->i_num;
if(j >= p_im->i_cols[i]) if( j >= p_im->i_cols[i] )
{ {
i++; j=0; 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, static void RenderDVBSUB( vout_thread_t *p_vout, picture_t *p_pic,
const subpicture_t *p_spu ) 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 ) if( p_spu->p_sys == NULL ) return;
{
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 */ /* I420 target, no scaling */
case VLC_FOURCC('I','4','2','2'): case VLC_FOURCC('I','4','2','2'):
case VLC_FOURCC('I','4','2','0'): case VLC_FOURCC('I','4','2','0'):
...@@ -1169,7 +1419,7 @@ static void RenderDVBSUB( vout_thread_t *p_vout, picture_t *p_pic, ...@@ -1169,7 +1419,7 @@ static void RenderDVBSUB( vout_thread_t *p_vout, picture_t *p_pic,
/* As long as we just use Y info, I422 and YV12 are just equivalent /* 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 * to I420. Remember to change it the day we'll take into account
* U and V info. */ * U and V info. */
RenderI42x( p_vout, p_pic, p_spu ); RenderI42x( p_vout, p_pic, p_render );
break; break;
/* RV16 target, scaling */ /* RV16 target, scaling */
...@@ -1187,123 +1437,154 @@ static void RenderDVBSUB( vout_thread_t *p_vout, picture_t *p_pic, ...@@ -1187,123 +1437,154 @@ static void RenderDVBSUB( vout_thread_t *p_vout, picture_t *p_pic,
/* NVidia overlay, no scaling */ /* NVidia overlay, no scaling */
case VLC_FOURCC('Y','U','Y','2'): case VLC_FOURCC('Y','U','Y','2'):
RenderYUY2( p_vout, p_pic, p_spu ); RenderYUY2( p_vout, p_pic, p_render );
break; break;
default: default:
msg_Err( p_vout, "unknown chroma, can't render SPU" ); msg_Err( p_vout, "unknown chroma, can't render SPU" );
break; 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 ) /* Allocate the subpicture internal data. */
{ #ifdef DEBUG_DVBSUB
dvbsub_region_t* p_region; if( !p_vout ) p_sys->p_spu = malloc( sizeof(subpicture_t) );
dvbsub_objectdef_t* p_objectdef; else
dvbsub_object_t* p_o; #endif
dvbsub_object_t* p_object; p_sys->p_spu =
dvbsub_object_t* p_object_old; vout_CreateSubPicture( p_vout, p_sys->i_subpic_channel,
dvbsub_render_t* p_render; MEMORY_SUBPICTURE );
dvbsub_rle_t* p_c; if( p_sys->p_spu == NULL ) return;
uint8_t i , j = 0;
/* Loop on region definitions */
/* loop on regions */ #ifdef DEBUG_DVBSUB
for( i = 0; i < dvbsub->p_page->i_regions_number; i++ ) 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 */ /* Loop on object definitions */
for( p_objectdef = p_region->p_object; p_objectdef != NULL; for( j = 0; j < p_region->i_object_defs; j++ )
p_objectdef = p_objectdef->p_next )
{ {
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 */ /* Look for the right object */
p_object = dvbsub->p_objects; for( p_object = p_sys->p_objects; p_object != NULL;
while( !p_object && p_object->i_id != p_objectdef->i_id ) 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 ) if( !p_object )
{ {
msg_Err( p_vout, "internal decoder error"); msg_Err( p_dec, "no object founddddd!!!" );
return; continue;
} }
/* Allocate the render structure */ /* Allocate the render structure */
p_render = malloc( sizeof(dvbsub_render_t) ); p_current = malloc( sizeof(dvbsub_render_t) );
p_render->i_x = p_region->i_x + p_objectdef->i_xoffset; p_current->p_next = NULL;
p_render->i_y = p_region->i_y + p_objectdef->i_yoffset; p_current->i_x = p_regiondef->i_x + p_objectdef->i_x;
p_render->p_rle_top = p_object->topfield; p_current->i_y = p_regiondef->i_y + p_objectdef->i_y;
p_render->p_rle_bot = p_object->bottomfield; 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( !p_render ) p_render = p_current;
if( !dvbsub->p_clut[p_region->i_clut] ) return; 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 */ /* 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 ) p_c->p_next != NULL; p_c = p_c->p_next )
{ {
//TODO We assume here we are working in 4bp dvbsub_color_t *p_color = (p_c->i_bpp == 2) ? p_clut->c_2b :
p_c->y = dvbsub->p_clut[p_region->i_clut]->c_4b[p_c->i_color_code].Y; (p_c->i_bpp == 4) ? p_clut->c_4b : p_clut->c_8b;
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->y = p_color[p_c->i_color_code].Y;
p_c->t = dvbsub->p_clut[p_region->i_clut]->c_4b[p_c->i_color_code].T; 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 ) p_c = p_c->p_next )
{ {
//TODO We assume here we are working in 4bp dvbsub_color_t *p_color = (p_c->i_bpp == 2) ? p_clut->c_2b :
p_c->y = dvbsub->p_clut[p_region->i_clut]->c_4b[p_c->i_color_code].Y; (p_c->i_bpp == 4) ? p_clut->c_4b : p_clut->c_8b;
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;
}
p_c->y = p_color[p_c->i_color_code].Y;
/* Allocate the subpicture internal data. */ p_c->cr = p_color[p_c->i_color_code].Cr;
dvbsub->p_spu[j] = p_c->cb = p_color[p_c->i_color_code].Cb;
vout_CreateSubPicture( p_vout, dvbsub->i_subpic_channel, p_c->t = p_color[p_c->i_color_code].T;
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;
} }
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 );
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment