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 @@
*
* 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
......@@ -31,6 +32,8 @@
#include "vlc_bits.h"
//#define DEBUG_DVBSUB 1
/*****************************************************************************
* Module descriptor.
*****************************************************************************/
......@@ -52,45 +55,67 @@ vlc_module_end();
/* 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;
......@@ -106,7 +131,11 @@ typedef struct dvbsub_region_s
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;
......@@ -117,23 +146,11 @@ typedef struct
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
......@@ -150,50 +167,49 @@ 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;
};
......@@ -219,18 +235,27 @@ struct decoder_sys_t
#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
......@@ -240,8 +265,9 @@ static void dvbsub( dvbsub_all_t * );
*****************************************************************************/
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') )
{
......@@ -251,12 +277,20 @@ static int Open( vlc_object_t *p_this )
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;
}
......@@ -270,7 +304,7 @@ static void Close( vlc_object_t *p_this )
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++ )
{
......@@ -284,8 +318,7 @@ static void Close( vlc_object_t *p_this )
}
}
dvbsub( &p_sys->dvbsub );
free_all( p_dec );
free( p_sys );
}
......@@ -305,120 +338,137 @@ static void Decode( decoder_t *p_dec, block_t **pp_block )
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 */
......@@ -430,45 +480,66 @@ static void decode_segment( decoder_t *p_dec, dvbsub_all_t *p_dvbspu, bs_t *s )
/* 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 ) );
......@@ -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 )
{
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 )
......@@ -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
* 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 );
......@@ -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_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;
......@@ -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 );
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 )
......@@ -758,22 +883,17 @@ static void decode_object( dvbsub_all_t *p_dvbsub, bs_t *s )
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;
......@@ -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 */
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;
}
}
......@@ -830,40 +948,113 @@ static dvbsub_image_t* dvbsub_parse_pdata( dvbsub_all_t *p_dvbsub, bs_t *s,
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
{
......@@ -873,7 +1064,7 @@ static uint16_t dvbsub_count0x11( bs_t *s, uint16_t* p,
{
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
{
......@@ -890,7 +1081,7 @@ static uint16_t dvbsub_count0x11( bs_t *s, uint16_t* p,
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
{
......@@ -899,26 +1090,26 @@ static uint16_t dvbsub_count0x11( bs_t *s, uint16_t* p,
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;
}
}
......@@ -931,98 +1122,157 @@ static uint16_t dvbsub_count0x11( bs_t *s, uint16_t* p,
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;
......@@ -1030,7 +1280,6 @@ static void RenderYUY2( vout_thread_t *p_vout, picture_t *p_pic,
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;
......@@ -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,
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'):
......@@ -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
* 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 */
......@@ -1187,123 +1437,154 @@ static void RenderDVBSUB( vout_thread_t *p_vout, picture_t *p_pic,
/* 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 );
}
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