Commit 0981604c authored by Laurent Aimar's avatar Laurent Aimar

* all: ported/cleaned up/renabled dvb subtitle decoder. But it is untested.

 (I have no sample at all)
parent 5bab317b
dnl Autoconf settings for vlc dnl Autoconf settings for vlc
dnl $Id: configure.ac,v 1.119 2003/11/23 18:40:09 fenrir Exp $ dnl $Id: configure.ac,v 1.120 2003/11/24 02:35:50 fenrir Exp $
AC_INIT(vlc,0.6.3-cvs) AC_INIT(vlc,0.6.3-cvs)
...@@ -867,7 +867,7 @@ dnl default modules ...@@ -867,7 +867,7 @@ dnl default modules
dnl dnl
AX_ADD_PLUGINS([dummy rc logger gestures memcpy hotkeys]) AX_ADD_PLUGINS([dummy rc logger gestures memcpy hotkeys])
AX_ADD_PLUGINS([mpgv mpga m4v mpeg_system ps ts avi asf aac mp4 rawdv]) AX_ADD_PLUGINS([mpgv mpga m4v mpeg_system ps ts avi asf aac mp4 rawdv])
AX_ADD_PLUGINS([spudec mpeg_audio lpcm a52 dts cinepak]) AX_ADD_PLUGINS([spudec dvbsub mpeg_audio lpcm a52 dts cinepak])
AX_ADD_PLUGINS([deinterlace invert adjust wall transform distort clone crop motionblur]) AX_ADD_PLUGINS([deinterlace invert adjust wall transform distort clone crop motionblur])
AX_ADD_PLUGINS([float32tos16 float32tos8 float32tou16 float32tou8 a52tospdif dtstospdif fixed32tofloat32 fixed32tos16 s16tofixed32 s16tofloat32 s16tofloat32swab s8tofloat32 u8tofixed32 u8tofloat32]) AX_ADD_PLUGINS([float32tos16 float32tos8 float32tou16 float32tou8 a52tospdif dtstospdif fixed32tofloat32 fixed32tos16 s16tofixed32 s16tofloat32 s16tofloat32swab s8tofloat32 u8tofixed32 u8tofloat32])
AX_ADD_PLUGINS([trivial_resampler ugly_resampler linear_resampler bandlimited_resampler]) AX_ADD_PLUGINS([trivial_resampler ugly_resampler linear_resampler bandlimited_resampler])
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* vlc_es.h * vlc_es.h
***************************************************************************** *****************************************************************************
* Copyright (C) 1999-2001 VideoLAN * Copyright (C) 1999-2001 VideoLAN
* $Id: vlc_es.h,v 1.4 2003/11/24 00:39:00 fenrir Exp $ * $Id: vlc_es.h,v 1.5 2003/11/24 02:35:50 fenrir Exp $
* *
* Authors: Laurent Aimar <fenrir@via.ecp.fr> * Authors: Laurent Aimar <fenrir@via.ecp.fr>
* *
...@@ -92,6 +92,11 @@ struct subs_format_t ...@@ -92,6 +92,11 @@ struct subs_format_t
/* FIXME */ /* FIXME */
uint32_t palette[16+1]; uint32_t palette[16+1];
} spu; } spu;
struct
{
int i_id;
} dvb;
}; };
/** /**
......
...@@ -16,3 +16,4 @@ SOURCES_rawvideo = rawvideo.c ...@@ -16,3 +16,4 @@ SOURCES_rawvideo = rawvideo.c
SOURCES_quicktime = quicktime.c SOURCES_quicktime = quicktime.c
SOURCES_subsdec = subsdec.c SOURCES_subsdec = subsdec.c
SOURCES_faad = faad.c SOURCES_faad = faad.c
SOURCES_dvbsub = dvbsub.c
...@@ -3,9 +3,10 @@ ...@@ -3,9 +3,10 @@
***************************************************************************** *****************************************************************************
* Copyright (C) 2003 ANEVIA * Copyright (C) 2003 ANEVIA
* Copyright (C) 2003 VideoLAN * Copyright (C) 2003 VideoLAN
* $Id: dvbsub.c,v 1.5 2003/11/24 00:39:01 fenrir Exp $ * $Id: dvbsub.c,v 1.6 2003/11/24 02:35:50 fenrir Exp $
* *
* Authors: Damien LUCAS <damien.lucas@anevia.com> * Authors: Damien LUCAS <damien.lucas@anevia.com>
* Laurent Aimar <fenrir@via.ecp.fr>
* *
* 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
...@@ -185,6 +186,10 @@ typedef struct ...@@ -185,6 +186,10 @@ typedef struct
typedef struct typedef struct
{ {
int i_id;
mtime_t i_pts;
dvbsub_clut_t* p_clut[0xff]; dvbsub_clut_t* p_clut[0xff];
dvbsub_page_t* p_page; dvbsub_page_t* p_page;
dvbsub_object_t* p_objects; dvbsub_object_t* p_objects;
...@@ -202,9 +207,10 @@ struct subpicture_sys_t ...@@ -202,9 +207,10 @@ struct subpicture_sys_t
struct decoder_sys_t struct decoder_sys_t
{ {
vout_thread_t *p_vout; vout_thread_t *p_vout;
mtime_t i_pts;
bs_t bs; bs_t bs;
dvbsub_all_t dvbsub;
}; };
...@@ -238,36 +244,10 @@ static void Decode ( decoder_t *, block_t ** ); ...@@ -238,36 +244,10 @@ static void Decode ( decoder_t *, block_t ** );
static vout_thread_t *FindVout( decoder_t * ); static vout_thread_t *FindVout( decoder_t * );
static void RenderI42x( vout_thread_t *, picture_t *, const subpicture_t *, static int dvbsub_init( dvbsub_all_t *, int );
vlc_bool_t ); static void dvbsub_decode_segment( dvbsub_all_t *p_dvbsub, bs_t *s );
static void RenderYUY2( vout_thread_t *, picture_t *, const subpicture_t *, static void dvbsub_render( dvbsub_all_t *, vout_thread_t * );
vlc_bool_t ); static void dvbsub_clean( dvbsub_all_t * );
static void dvbsub_clut_add_entry ( dvbsub_clut_t* clut, uint8_t type,
uint8_t id, uint8_t y, uint8_t cr,
uint8_t cb, uint8_t t);
static void dvbsub_add_objectdef_to_region ( dvbsub_objectdef_t* p_obj,
dvbsub_region_t* p_region );
static dvbsub_image_t* dvbsub_parse_pdata ( dvbsub_thread_t* ,uint16_t );
static uint16_t dvbsub_count0x11(dvbsub_thread_t* p_spudec,
uint16_t* p,
dvbsub_image_t* p_image);
static void dvbsub_decode_segment ( dvbsub_thread_t *, dvbsub_all_t* );
static void dvbsub_decode_page_composition ( dvbsub_thread_t *, dvbsub_all_t* );
static void dvbsub_decode_region_composition ( dvbsub_thread_t*, dvbsub_all_t*);
static void dvbsub_decode_object ( dvbsub_thread_t*, dvbsub_all_t* );
static vlc_bool_t dvbsub_check_page ( dvbsub_all_t* );
static void dvbsub_render ( dvbsub_thread_t *p_spudec,dvbsub_all_t* );
static int dvbsub_parse ( dvbsub_thread_t *p_spudec, dvbsub_all_t* dvbsub );
static void dvbsub_decode_clut ( dvbsub_thread_t*, dvbsub_all_t*);
static void dvbsub_stop_display ( dvbsub_thread_t* p_dec, dvbsub_all_t* dvbsub);
static void free_image (dvbsub_image_t* p_i);
static void free_object (dvbsub_object_t* p_o);
static void free_regions (dvbsub_region_t* p_r, uint8_t nb);
static void free_objects (dvbsub_object_t* p_o);
static void free_clut ( dvbsub_clut_t* p_c);
static void free_page (dvbsub_page_t* p_p);
static void free_all ( dvbsub_all_t* p_a );
/***************************************************************************** /*****************************************************************************
...@@ -286,11 +266,12 @@ static int Open( vlc_object_t *p_this ) ...@@ -286,11 +266,12 @@ static int Open( vlc_object_t *p_this )
return VLC_EGENERIC; return VLC_EGENERIC;
} }
p_dec->pf_decode_subs = 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->p_vout = NULL;
p_sys->i_pts = 0;
dvbsub_init( &p_sys->dvbsub, p_dec->fmt_in.subs.dvb.i_id );
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' ) );
...@@ -313,86 +294,73 @@ static void Close( vlc_object_t *p_this ) ...@@ -313,86 +294,73 @@ static void Close( vlc_object_t *p_this )
{ {
p_subpic = &p_sys->p_vout->p_subpicture[i_subpic]; p_subpic = &p_sys->p_vout->p_subpicture[i_subpic];
if( p_subpic != NULL && if( p_subpic != NULL &&
( ( p_subpic->i_status == RESERVED_SUBPICTURE ) ( ( p_subpic->i_status == RESERVED_SUBPICTURE ) ||
|| ( p_subpic->i_status == READY_SUBPICTURE ) ) ) ( p_subpic->i_status == READY_SUBPICTURE ) ) )
{ {
vout_DestroySubPicture( p_sys->p_vout, p_subpic ); vout_DestroySubPicture( p_sys->p_vout, p_subpic );
} }
} }
} }
trox_call(); dvbsub_clean( &p_sys->dvbsub );
free( p_sys );
} }
/***************************************************************************** /*****************************************************************************
* RunDecoder: this function is called just after the thread is created * Decode:
*****************************************************************************/ *****************************************************************************/
static int RunDecoder( decoder_fifo_t * p_fifo ) static void Decode( decoder_t *p_dec, block_t **pp_block )
{ {
dvbsub_thread_t * p_dvbsubdec; decoder_sys_t *p_sys = p_dec->p_sys;
// vout_thread_t * p_vout_backup = NULL; block_t *p_block;
dvbsub_all_t dvbsub;
unsigned int k; if( pp_block == NULL || *pp_block == NULL )
/* Allocate the memory needed to store the thread's structure */
p_dvbsubdec = (dvbsub_thread_t *)trox_malloc( sizeof(dvbsub_thread_t) );
if ( p_dvbsubdec == NULL )
{ {
msg_Err( p_fifo, "out of memory" ); return;
DecoderError( p_fifo );
return( -1 );
} }
/* p_block = *pp_block;
* Initialize the thread properties *pp_block = NULL;
*/
p_dvbsubdec->p_vout = NULL; p_sys->dvbsub.i_pts = p_block->i_pts;
p_dvbsubdec->p_fifo = p_fifo; if( p_sys->dvbsub.i_pts <= 0 )
/*
* Initialize thread and free configuration
*/
p_dvbsubdec->p_fifo->b_error = InitThread( p_dvbsubdec );
dvbsub.p_page=NULL;
dvbsub.p_objects=NULL;
for(k=0; k<0xff; k++) dvbsub.p_clut[k] = NULL;
for(k=0; k<16; k++) dvbsub.p_spu[k] = NULL;
/*
* Main loop - it is not executed if an error occured during
* initialization
*/
while( (!p_dvbsubdec->p_fifo->b_die) && (!p_dvbsubdec->p_fifo->b_error) )
{ {
dvbsub_parse( p_dvbsubdec, &dvbsub ); msg_Warn( p_dec, "non dated subtitle" );
p_dvbsubdec->p_vout = FindVout( p_dvbsubdec ); block_Release( p_block );
if( p_dvbsubdec->p_vout ) return;
}
if( ( p_sys->p_vout = FindVout( p_dec ) ) )
{
int i_data_identifier;
int i_subtitle_stream_id;
int i_end_data_marker;
bs_init( &p_sys->bs, p_block->p_buffer, p_block->i_buffer );
i_data_identifier = bs_read( &p_sys->bs, 8 );
i_subtitle_stream_id = bs_read( &p_sys->bs, 8 );
for( ;; )
{ {
// Check if the page is to be displayed if( bs_show( &p_sys->bs, 8 ) != 0x0f )
if(dvbsub_check_page(&dvbsub))
{ {
dvbsub_render(p_dvbsubdec, &dvbsub); break;
} }
vlc_object_release( p_dvbsubdec->p_vout ); dvbsub_decode_segment( &p_sys->dvbsub, &p_sys->bs );
} }
i_end_data_marker = bs_read( &p_sys->bs, 8 );
/* Check if the page is to be displayed */
if( p_sys->dvbsub.p_page && p_sys->dvbsub.p_objects )
{
dvbsub_render( &p_sys->dvbsub, p_sys->p_vout );
}
vlc_object_release( p_sys->p_vout );
} }
// Free all structures
//dvbsub.p_objects=NULL; block_Release( p_block );
//for(k=0; k<16; k++)
// if(dvbsub.p_spu[k] != NULL)
// dvbsub.p_spu[k]->p_sys->b_obsolete = 1;
/*
* Error loop
*/
if( p_dvbsubdec->p_fifo->b_error )
{
DecoderError( p_dvbsubdec->p_fifo );
/* End of thread */
EndThread( p_dvbsubdec, &dvbsub );
return -1;
}
/* End of thread */
EndThread( p_dvbsubdec, &dvbsub );
free_all(&dvbsub);
return 0;
} }
/* following functions are local */ /* following functions are local */
...@@ -418,416 +386,414 @@ static vout_thread_t *FindVout( decoder_t *p_dec ) ...@@ -418,416 +386,414 @@ static vout_thread_t *FindVout( decoder_t *p_dec )
} }
} }
/*****************************************************************************
* EndThread: thread destruction static int dvbsub_init( dvbsub_all_t *p_dvbsub, int i_id )
*****************************************************************************
* This function is called when the thread ends after a sucessful
* initialization.
*****************************************************************************/
static void EndThread( dvbsub_thread_t *p_dvbsubdec, dvbsub_all_t* p_dvbsub )
{ {
if( p_dvbsubdec->p_vout != NULL int i;
&& p_dvbsubdec->p_vout->p_subpicture != NULL )
memset( p_dvbsub, 0, sizeof( dvbsub_all_t ) );
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++ )
{ {
subpicture_t * p_subpic; p_dvbsub->p_clut[i] = NULL;
int i_subpic; }
for( i_subpic = 0; i_subpic < VOUT_MAX_SUBPICTURES; i_subpic++ ) for( i = 0; i < 16; i++ )
{ {
p_subpic = &p_dvbsubdec->p_vout->p_subpicture[i_subpic]; p_dvbsub->p_spu[i] = NULL;
if( p_subpic != NULL &&
( ( p_subpic->i_status == RESERVED_SUBPICTURE )
|| ( p_subpic->i_status == READY_SUBPICTURE ) ) )
{
vout_DestroySubPicture( p_dvbsubdec->p_vout, p_subpic );
}
}
} }
CloseBitstream( &p_dvbsubdec->bit_stream ); return 0;
trox_free( p_dvbsubdec );
trox_call();
} }
static void free_all( dvbsub_all_t * );
static int dvbsub_parse ( dvbsub_thread_t *p_spudec, static void dvbsub_clean( dvbsub_all_t *p_dvbsub )
dvbsub_all_t* dvbsub )
{ {
unsigned int data_identifier; free_all( p_dvbsub );
unsigned int subtitle_stream_id; trox_call() ;
unsigned int nextbits;
uint32_t end_data_marker;
/* Re-align the buffer on an 8-bit boundary */
RealignBits( &p_spudec->bit_stream );
data_identifier = GetBits( &p_spudec->bit_stream, 8 );
subtitle_stream_id = GetBits( &p_spudec->bit_stream, 8 );
nextbits = ShowBits( &p_spudec->bit_stream, 8 );
while(nextbits == 0x0f )
{
dvbsub_decode_segment( p_spudec, dvbsub );
nextbits = ShowBits( &p_spudec->bit_stream, 8 );
}
end_data_marker = GetBits( &p_spudec->bit_stream, 8 );
return 0;
} }
static void dvbsub_decode_clut( dvbsub_all_t *p_dvbsub, bs_t *s );
static void dvbsub_decode_page_composition( dvbsub_all_t *p_dvbsub, bs_t *s);
static void dvbsub_decode_region_composition( dvbsub_all_t *p_dvbsub, bs_t *s );
static void dvbsub_stop_display( dvbsub_all_t* p_dvbsub );
static void dvbsub_decode_object( dvbsub_all_t *p_dvbsub, bs_t *s );
static void dvbsub_decode_segment ( dvbsub_thread_t * p_spudec, static void free_page (dvbsub_page_t* p_p);
dvbsub_all_t * dvbsub )
static void dvbsub_decode_segment( dvbsub_all_t *p_dvbspu, bs_t *s )
{ {
unsigned int sync_byte; int i_type;
unsigned int segment_type; int i_page_id;
uint16_t page_id; int i_size;
uint16_t segment_length;
int k; /* sync_byte */
sync_byte = GetBits( &p_spudec->bit_stream, 8 ); bs_skip( s, 8 );
segment_type = GetBits( &p_spudec->bit_stream, 8 );
page_id = GetBits( &p_spudec->bit_stream, 16 ); /* segment type */
segment_length = ShowBits( &p_spudec->bit_stream, 16 ); i_type = bs_read( s, 8 );
if( page_id != ((dvb_spuinfo_t*)p_spudec->p_fifo->p_spuinfo)->i_id )
/* page id */
i_page_id = bs_read( s, 16 );
/* segment size */
i_size = bs_show( s, 16 );
if( i_page_id != p_dvbspu->i_id )
{ {
//TODO should use GetChunk bs_skip( s, 8 * ( 2 + i_size ) );
for(k=0; k<segment_length+2; k++) GetBits( &p_spudec->bit_stream, 8 );
return; return;
} }
switch( segment_type )
switch( i_type )
{ {
case DVBSUB_ST_CLUT_DEFINITION: case DVBSUB_ST_CLUT_DEFINITION:
dvbsub_decode_clut ( p_spudec, dvbsub ); dvbsub_decode_clut( p_dvbspu, s );
break; break;
case DVBSUB_ST_PAGE_COMPOSITION: case DVBSUB_ST_PAGE_COMPOSITION:
dvbsub_decode_page_composition ( p_spudec, dvbsub ); dvbsub_decode_page_composition( p_dvbspu, s );
break; break;
case DVBSUB_ST_REGION_COMPOSITION: case DVBSUB_ST_REGION_COMPOSITION:
dvbsub_decode_region_composition ( p_spudec, dvbsub ); dvbsub_decode_region_composition( p_dvbspu, s );
break; break;
case DVBSUB_ST_OBJECT_DATA: case DVBSUB_ST_OBJECT_DATA:
dvbsub_decode_object ( p_spudec, dvbsub ); dvbsub_decode_object( p_dvbspu, s );
break; break;
case DVBSUB_ST_ENDOFDISPLAY: case DVBSUB_ST_ENDOFDISPLAY:
dvbsub_stop_display ( p_spudec, dvbsub); dvbsub_stop_display( p_dvbspu );
break; break;
case DVBSUB_ST_STUFFING: case DVBSUB_ST_STUFFING:
default: default:
fprintf(stderr, "*** DVBSUB - Unsupported segment type ! (%04x)\n", fprintf( stderr, "*** DVBSUB - Unsupported segment type ! (%04x)",
segment_type ); i_type );
GetBits( &p_spudec->bit_stream, 16 ); bs_skip( s, 8 * ( 2 + i_size ) );
for(k=0; k<segment_length; k++)
GetBits( &p_spudec->bit_stream, 8 );
break; break;
} }
return;
}
static void dvbsub_decode_page_composition (dvbsub_thread_t *p_spudec,
dvbsub_all_t *dvbsub)
{
unsigned int i_version_number;
unsigned int i_state;
unsigned int i_segment_length;
uint8_t i_timeout;
unsigned int k;
i_segment_length = GetBits( &p_spudec->bit_stream, 16 );
//A page is composed by one or more region:
i_timeout = GetBits( &p_spudec->bit_stream, 8 );
i_version_number = GetBits( &p_spudec->bit_stream, 4 );
i_state = GetBits( &p_spudec->bit_stream, 2 );
// TODO We assume it is a new page (i_state)
if (dvbsub->p_page) free_page(dvbsub->p_page);
GetBits( &p_spudec->bit_stream, 2 ); /* Reserved */
//Allocate a new page
dvbsub->p_page = trox_malloc (sizeof(dvbsub_page_t));
dvbsub->p_page->i_timeout = i_timeout;
// Number of regions:
dvbsub->p_page->i_regions_number = (i_segment_length-2) / 6;
/* Special workaround for CAVENA encoders
* a page with no regions is sent instead of a 0x80 packet (End Of Display) */
if( dvbsub->p_page->i_regions_number == 0 )
{
dvbsub_stop_display(p_spudec, dvbsub );
}
/* /Special workaround */
dvbsub->p_page->regions =
trox_malloc(dvbsub->p_page->i_regions_number*sizeof(dvbsub_region_t));
for(k=0; k<dvbsub->p_page->i_regions_number ; k++)
{
dvbsub->p_page->regions[k].i_id = GetBits( &p_spudec->bit_stream, 8 );
GetBits( &p_spudec->bit_stream, 8 ); /* Reserved */
dvbsub->p_page->regions[k].i_x = GetBits( &p_spudec->bit_stream, 16 );
dvbsub->p_page->regions[k].i_y = GetBits( &p_spudec->bit_stream, 16 );
dvbsub->p_page->regions[k].p_object = NULL;
}
} }
static void dvbsub_stop_display( dvbsub_all_t *p_dvbsub )
static void dvbsub_decode_region_composition (dvbsub_thread_t *p_spudec,
dvbsub_all_t *dvbsub)
{ {
unsigned int i_segment_length; int i;
unsigned int i_processed_length;
unsigned int i_region_id;
dvbsub_region_t* p_region;
unsigned int k;
p_region = NULL;
i_segment_length = GetBits( &p_spudec->bit_stream, 16 );
// Get region id:
i_region_id = GetBits( &p_spudec->bit_stream, 8 );
for(k=0; k<dvbsub->p_page->i_regions_number; k++)
{
if ( dvbsub->p_page->regions[k].i_id == i_region_id )
p_region = &(dvbsub->p_page->regions[k]);
}
if(p_region == NULL)
{
// TODO
// The region has never been declared before
// Internal error
fprintf (stderr, "Decoding of undeclared region N/A...\n");
return;
}
// Skip version number and fill flag
if (ShowBits( &p_spudec->bit_stream, 4 ) == p_region->i_version_number)
{
fprintf(stderr, "Skipping already known region N/A ...\n");
// TODO Skip the right number of bits
}
// Region attributes
p_region->i_version_number = GetBits( &p_spudec->bit_stream, 4 );
p_region->b_fill = GetBits( &p_spudec->bit_stream, 1 );
GetBits( &p_spudec->bit_stream, 3 ); /* Reserved */
p_region->i_width = GetBits( &p_spudec->bit_stream, 16 );
p_region->i_height = GetBits( &p_spudec->bit_stream, 16 );
p_region->i_level_comp = GetBits( &p_spudec->bit_stream, 3 );
p_region->i_depth = GetBits( &p_spudec->bit_stream, 3 );
GetBits( &p_spudec->bit_stream, 2 ); /* Reserved */
p_region->i_clut = GetBits( &p_spudec->bit_stream, 8 );
p_region->i_8bp_code = GetBits( &p_spudec->bit_stream, 8 );
p_region->i_4bp_code = GetBits( &p_spudec->bit_stream, 4 );
p_region->i_2bp_code = GetBits( &p_spudec->bit_stream, 2 );
GetBits( &p_spudec->bit_stream, 2 ); /* Reserved */
// List of objects in the region:
// We already skipped 10 bytes
i_processed_length = 10;
while ( i_processed_length < i_segment_length )
{
// We create a new object
dvbsub_objectdef_t* p_obj;
p_obj = trox_malloc(sizeof(dvbsub_objectdef_t));
// We parse object properties
p_obj->i_id = GetBits( &p_spudec->bit_stream, 16 );
p_obj->i_type = GetBits( &p_spudec->bit_stream, 2 );
p_obj->i_provider = GetBits( &p_spudec->bit_stream, 2 );
p_obj->i_xoffset = GetBits( &p_spudec->bit_stream, 12 );
GetBits( &p_spudec->bit_stream, 4 ); /* Reserved */
p_obj->i_yoffset = GetBits( &p_spudec->bit_stream, 12 );
i_processed_length += 6;
if ( p_obj->i_type == DVBSUB_OT_BASIC_CHAR
|| p_obj->i_type == DVBSUB_OT_COMPOSITE_STRING )
{
p_obj->i_fg_pc = GetBits( &p_spudec->bit_stream, 8 );
p_obj->i_bg_pc = GetBits( &p_spudec->bit_stream, 8 );
i_processed_length += 2;
}
p_obj->p_next = NULL;
dvbsub_add_objectdef_to_region(p_obj, p_region);
}
}
for( i = 0; p_dvbsub->p_spu[i] != NULL; i++ )
static void dvbsub_decode_object (dvbsub_thread_t* p_spudec,
dvbsub_all_t* dvbsub)
{
dvbsub_object_t* p_obj;
dvbsub_object_t* p_o;
uint16_t i_segment_length;
uint16_t i_topfield_length;
uint16_t i_bottomfield_length;
// Memory Allocation
p_obj = trox_malloc ( sizeof ( dvbsub_object_t ) );
p_obj->p_next=NULL;
i_segment_length = GetBits( &p_spudec->bit_stream, 16 );
p_obj->i_id = GetBits( &p_spudec->bit_stream, 16 );
p_obj->i_version_number = GetBits( &p_spudec->bit_stream, 4 );
// TODO Check we don't already have this object / this version
p_obj->i_coding_method = GetBits( &p_spudec->bit_stream, 2 );
p_obj->b_non_modify_color = GetBits( &p_spudec->bit_stream, 1 );
GetBits( &p_spudec->bit_stream, 1 ); /* Reserved */
if(p_obj->i_coding_method == 0x00)
{
i_topfield_length = GetBits( &p_spudec->bit_stream, 16 );
i_bottomfield_length = GetBits( &p_spudec->bit_stream, 16 );
p_obj->topfield = dvbsub_parse_pdata (p_spudec, i_topfield_length);
p_obj->bottomfield =
dvbsub_parse_pdata (p_spudec, i_bottomfield_length);
}
else
{ {
GetBits(&p_spudec->bit_stream, (i_segment_length -3) *8); p_dvbsub->p_spu[i]->i_stop = p_dvbsub->i_pts;
//TODO
// DVB subtitling as characters
} }
// Add this object to the list of the page
p_o = dvbsub->p_objects;
dvbsub->p_objects = p_obj;
p_obj->p_next = p_o;
return;
} }
static void dvbsub_stop_display ( dvbsub_thread_t* p_dec, static void dvbsub_decode_clut( dvbsub_all_t *p_dvbsub, bs_t *s )
dvbsub_all_t* dvbsub)
{
unsigned int j;
for(j = 0; dvbsub->p_spu[j] != NULL; j++)
dvbsub->p_spu[j]->i_stop = p_dec->bit_stream.p_pes->i_pts;
return;
}
static void dvbsub_decode_clut ( dvbsub_thread_t* p_dec,
dvbsub_all_t* dvbsub)
{ {
uint16_t i_segment_length; uint16_t i_segment_length;
uint16_t i_processed_length; uint16_t i_processed_length;
uint8_t i_entry_id;
uint8_t i_entry_type;
dvbsub_clut_t* clut; dvbsub_clut_t* clut;
uint8_t i_clut_id; uint8_t i_clut_id;
uint8_t i_version_number; uint8_t i_version_number;
uint8_t y;
uint8_t cr; i_segment_length = bs_read( s, 16 );
uint8_t cb; i_clut_id = bs_read( s, 8 );
uint8_t t; i_version_number = bs_read( s, 4 );
i_segment_length = GetBits( &p_dec->bit_stream, 16 );
i_clut_id = GetBits( &p_dec->bit_stream, 8 );
i_version_number = GetBits( &p_dec->bit_stream, 4 );
// Check that this id doesn't not already exist // Check that this id doesn't not already exist
// with the same version number // with the same version number
// And allocate memory if necessary // And allocate memory if necessary
if( dvbsub->p_clut[i_clut_id] != NULL) if( p_dvbsub->p_clut[i_clut_id] != NULL)
{ {
if ( dvbsub->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 //TODO skip the right number of bits
return; return;
} }
else else
{ {
memset(dvbsub->p_clut[i_clut_id], 0, sizeof(dvbsub_clut_t)); memset( p_dvbsub->p_clut[i_clut_id], 0, sizeof(dvbsub_clut_t) );
} }
} }
else else
{ {
dvbsub->p_clut[i_clut_id] = trox_malloc(sizeof(dvbsub_clut_t)); p_dvbsub->p_clut[i_clut_id] = trox_malloc( sizeof(dvbsub_clut_t) );
} }
clut = dvbsub->p_clut[i_clut_id]; clut = p_dvbsub->p_clut[i_clut_id];
/* We don't have this version of the CLUT: /* We don't have this version of the CLUT:
* Parse it */ * Parse it */
clut->i_version_number = i_version_number; clut->i_version_number = i_version_number;
GetBits( &p_dec->bit_stream, 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 )
{ {
i_entry_id = GetBits( &p_dec->bit_stream, 8 ); uint8_t y, cb, cr, t;
i_entry_type = GetBits( &p_dec->bit_stream, 3 ); uint8_t i_id;
GetBits( &p_dec->bit_stream, 4 ); uint8_t i_type;
if ( GetBits( &p_dec->bit_stream, 1 )==0x01 )
i_id = bs_read( s, 8 );
i_type = bs_read( s, 3 );
bs_skip( s, 4 );
if( bs_read( s, 1 ) )
{ {
y = GetBits( &p_dec->bit_stream, 8 ); y = bs_read( s, 8 );
cr = GetBits( &p_dec->bit_stream, 8 ); cr = bs_read( s, 8 );
cb = GetBits( &p_dec->bit_stream, 8 ); cb = bs_read( s, 8 );
t = GetBits( &p_dec->bit_stream, 8 ); t = bs_read( s, 8 );
i_processed_length += 6; i_processed_length += 6;
} }
else else
{ {
y = GetBits( &p_dec->bit_stream, 6 ); y = bs_read( s, 6 );
cr = GetBits( &p_dec->bit_stream, 4 ); cr = bs_read( s, 4 );
cb = GetBits( &p_dec->bit_stream, 4 ); cb = bs_read( s, 4 );
t = GetBits( &p_dec->bit_stream, 2 ); t = bs_read( s, 2 );
i_processed_length += 4; i_processed_length += 4;
}
/* 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. */
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;
}
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;
}
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;
} }
dvbsub_clut_add_entry(clut, i_entry_type, i_entry_id, y, cr, cb, t); }
}
static void dvbsub_decode_page_composition( dvbsub_all_t *p_dvbsub, bs_t *s )
{
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: */
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 = trox_malloc( sizeof(dvbsub_page_t) );
p_dvbsub->p_page->i_timeout = i_timeout;
/* Number of regions: */
p_dvbsub->p_page->i_regions_number = (i_segment_length-2) / 6;
/* 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 )
{
dvbsub_stop_display( p_dvbsub );
}
/* /Special workaround */
p_dvbsub->p_page->regions =
trox_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_dvbsub->p_page->regions[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;
} }
} }
static void dvbsub_clut_add_entry ( dvbsub_clut_t* clut, uint8_t type, static void dvbsub_decode_region_composition( dvbsub_all_t *p_dvbsub, bs_t *s )
uint8_t id, uint8_t y, uint8_t cr,
uint8_t cb, uint8_t t)
{ {
/* According to EN 300-743 section 7.2.3 note 1, type should dvbsub_region_t* p_region = NULL;
* not have more than 1 bit set to one unsigned int i_segment_length;
But, some strams don't respect this note. */ unsigned int i_processed_length;
if( type & 0x04) unsigned int i_region_id;
unsigned int i;
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++ )
{
if( p_dvbsub->p_page->regions[i].i_id == i_region_id )
{
p_region = &(p_dvbsub->p_page->regions[i]);
}
}
if( p_region == NULL )
{ {
clut->c_2b[id].Y = y; /* TODO
clut->c_2b[id].Cr = cr; * The region has never been declared before
clut->c_2b[id].Cb = cb; * Internal error */
clut->c_2b[id].T = t; fprintf( stderr, "Decoding of undeclared region N/A...\n" );
return;
} }
if( type & 0x02)
/* Skip version number and fill flag */
if( bs_show( s, 4 ) == p_region->i_version_number )
{ {
clut->c_4b[id].Y = y; fprintf( stderr, "Skipping already known region N/A ...\n" );
clut->c_4b[id].Cr = cr; /* TODO Skip the right number of bits */
clut->c_4b[id].Cb = cb;
clut->c_4b[id].T = t;
} }
if( type & 0x01)
/* Region attributes */
p_region->i_version_number = bs_read( s, 4 );
p_region->b_fill = bs_read( s, 1 );
bs_skip( s, 3 ); /* Reserved */
p_region->i_width = bs_read( s, 16 );
p_region->i_height = bs_read( s, 16 );
p_region->i_level_comp = bs_read( s, 3 );
p_region->i_depth = bs_read( s, 3 );
bs_skip( s, 2 ); /* Reserved */
p_region->i_clut = bs_read( s, 8 );
p_region->i_8bp_code = bs_read( s, 8 );
p_region->i_4bp_code = bs_read( s, 4 );
p_region->i_2bp_code = bs_read( s, 2 );
bs_skip( s, 2 ); /* Reserved */
/* List of objects in the region: */
/* We already skipped 10 bytes */
i_processed_length = 10;
while( i_processed_length < i_segment_length )
{ {
clut->c_8b[id].Y = y; /* We create a new object */
clut->c_8b[id].Cr = cr; dvbsub_objectdef_t *p_obj = trox_malloc(sizeof(dvbsub_objectdef_t));
clut->c_8b[id].Cb = cb;
clut->c_8b[id].T = t; /* We parse object properties */
p_obj->p_next = NULL;
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 );
bs_skip( s, 4 ); /* Reserved */
p_obj->i_yoffset = bs_read( s, 12 );
i_processed_length += 6;
if( p_obj->i_type == DVBSUB_OT_BASIC_CHAR ||
p_obj->i_type == DVBSUB_OT_COMPOSITE_STRING )
{
p_obj->i_fg_pc = bs_read( s, 8 );
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;
}
} }
return;
} }
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 void dvbsub_add_objectdef_to_region ( dvbsub_objectdef_t* p_obj, static void dvbsub_decode_object( dvbsub_all_t *p_dvbsub, bs_t *s )
dvbsub_region_t* p_region )
{ {
dvbsub_objectdef_t* p_o = p_region->p_object; dvbsub_object_t *p_obj;
// Seek to the last non null element uint16_t i_segment_length;
if(p_o!=NULL)
/* Memory Allocation */
p_obj = trox_malloc ( sizeof ( dvbsub_object_t ) );
p_obj->p_next = NULL;
i_segment_length = bs_read( s, 16 );
/* 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 );
bs_skip( s, 1 ); /* Reserved */
if( p_obj->i_coding_method == 0x00 )
{ {
for(; p_o->p_next!=NULL; p_o=p_o->p_next); uint16_t i_topfield_length;
p_o->p_next = p_obj; uint16_t i_bottomfield_length;
p_o->p_next->p_next = NULL;
i_topfield_length = bs_read( s, 16 );
i_bottomfield_length= bs_read( s, 16 );
p_obj->topfield = dvbsub_parse_pdata( p_dvbsub, s, i_topfield_length );
p_obj->bottomfield = dvbsub_parse_pdata( p_dvbsub, s, i_bottomfield_length );
} }
else else
{ {
p_region->p_object = p_obj; bs_skip( s, (i_segment_length - 3 ) * 8 );
p_region->p_object->p_next = NULL; /*TODO
* DVB subtitling as characters */
} }
return;
}
/* 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_thread_t* p_spudec, static dvbsub_image_t* dvbsub_parse_pdata( dvbsub_all_t *p_dvbsub, bs_t *s, uint16_t length )
uint16_t length )
{ {
dvbsub_image_t* p_image; dvbsub_image_t* p_image;
uint16_t i_processed_length=0; uint16_t i_processed_length=0;
uint16_t i_lines=0; uint16_t i_lines=0;
uint16_t i_cols_last=0; uint16_t i_cols_last=0;
p_image = trox_malloc ( sizeof ( dvbsub_image_t) ); p_image = trox_malloc ( sizeof ( dvbsub_image_t) );
p_image->p_last=NULL; p_image->p_last=NULL;
memset(p_image->i_cols, 0, 576*sizeof(uint16_t)); memset(p_image->i_cols, 0, 576*sizeof(uint16_t));
/* 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)
{ {
switch(GetBits( &p_spudec->bit_stream, 8 )) switch( bs_read( s, 8 ) )
{ {
case 0x10: case 0x10:
fprintf(stderr, "0x10 N/A\n"); fprintf(stderr, "0x10 N/A\n");
break; break;
case 0x11: case 0x11:
i_processed_length += 1 + dvbsub_count0x11(p_spudec, i_processed_length +=
&(p_image->i_cols[i_lines]), 1 + dvbsub_count0x11( s, &(p_image->i_cols[i_lines]),
p_image); p_image );
break; break;
case 0x12: case 0x12:
fprintf(stderr, "0x12 N/A\n"); fprintf(stderr, "0x12 N/A\n");
...@@ -847,23 +813,28 @@ static dvbsub_image_t* dvbsub_parse_pdata ( dvbsub_thread_t* p_spudec, ...@@ -847,23 +813,28 @@ static dvbsub_image_t* dvbsub_parse_pdata ( dvbsub_thread_t* p_spudec,
break; break;
} }
} }
p_image->i_rows = i_lines; p_image->i_rows = i_lines;
p_image->i_cols[i_lines] = i_cols_last; p_image->i_cols[i_lines] = i_cols_last;
// Check word-aligned bits
if(ShowBits( &p_spudec->bit_stream, 8 )==0x00) /* Check word-aligned bits */
GetBits( &p_spudec->bit_stream, 8 ); if( bs_show( s, 8 ) == 0x00 )
{
bs_skip( s, 8 );
}
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 )
{ {
if(p->p_last != NULL) if(p->p_last != NULL)
{ {
p->p_last->p_next = trox_malloc (sizeof (dvbsub_rle_t)); p->p_last->p_next = trox_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 = trox_malloc (sizeof (dvbsub_rle_t)); p->p_codes = trox_malloc (sizeof (dvbsub_rle_t));
...@@ -872,97 +843,90 @@ static void add_rle_code (dvbsub_image_t* p, uint16_t num, uint8_t color) ...@@ -872,97 +843,90 @@ static void add_rle_code (dvbsub_image_t* p, uint16_t num, uint8_t color)
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->p_next = NULL; p->p_last->p_next = NULL;
return;
} }
static uint16_t dvbsub_count0x11(dvbsub_thread_t* p_spudec, uint16_t* p, dvbsub_image_t* p_image) static uint16_t dvbsub_count0x11( bs_t *s, uint16_t* p, 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 = GetBits( &p_spudec->bit_stream, 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_rle_code (p_image, 1, i_color ); /* 1 pixel of color code '0000' */
add_rle_code( p_image, 1, i_color );
} }
else else
{ {
if(GetBits( &p_spudec->bit_stream, 1 ) == 0x00) // Switch1 if( bs_read( s, 1 ) == 0x00 ) // Switch1
{ {
if( ShowBits( &p_spudec->bit_stream, 3 ) != 0x00 ) if( bs_show( s, 3 ) != 0x00 )
{ {
i_count = 2 + GetBits( &p_spudec->bit_stream, 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 );
} }
else else
{ {
GetBits( &p_spudec->bit_stream, 3); bs_skip( s, 3 );
b_stop=1; b_stop=1;
} }
i_processed += 8; i_processed += 8;
} }
else else
{ {
if(GetBits( &p_spudec->bit_stream, 1 ) == 0x00) //Switch2 if( bs_read( s, 1 ) == 0x00) //Switch2
{ {
i_count = 4 + GetBits( &p_spudec->bit_stream, 2 ); i_count = 4 + bs_read( s, 2 );
i_color = GetBits( &p_spudec->bit_stream, 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 );
} }
else else
{ {
switch ( GetBits( &p_spudec->bit_stream, 2 ) ) //Switch3 switch ( bs_read( s, 2 ) ) //Switch3
{ {
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 );
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 );
break; break;
case 0x2: case 0x2:
i_count = 9 + GetBits( &p_spudec->bit_stream, 4 ); i_count = 9 + bs_read( s, 4 );
i_color = GetBits( &p_spudec->bit_stream, 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 );
break; break;
case 0x3: case 0x3:
i_count= 25 + GetBits( &p_spudec->bit_stream, 8 ); i_count= 25 + bs_read( s, 8 );
i_color = GetBits( &p_spudec->bit_stream, 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 );
break; break;
} }
} }
} }
} }
} }
RealignBits ( &p_spudec->bit_stream );
return (i_processed+7)/8 ;
}
static vlc_bool_t dvbsub_check_page(dvbsub_all_t* dvbsub) bs_align( s );
{
if(dvbsub->p_page != NULL) return ( i_processed + 7 ) / 8 ;
{
if(dvbsub->p_objects != NULL)
return VLC_TRUE;
}
return VLC_FALSE;
} }
static void free_image (dvbsub_image_t* p_i) static void free_image (dvbsub_image_t* p_i)
...@@ -1021,7 +985,10 @@ static void free_objects (dvbsub_object_t* p_o) ...@@ -1021,7 +985,10 @@ static void free_objects (dvbsub_object_t* p_o)
} }
} }
static void free_clut ( dvbsub_clut_t* p_c) { trox_free(p_c); } static void free_clut ( dvbsub_clut_t* p_c )
{
trox_free(p_c);
}
static void free_page (dvbsub_page_t* p_p) static void free_page (dvbsub_page_t* p_p)
{ {
...@@ -1050,53 +1017,10 @@ static void free_all ( dvbsub_all_t* p_a ) ...@@ -1050,53 +1017,10 @@ static void free_all ( dvbsub_all_t* p_a )
for(i=0; i<16; i++) if (p_a->p_spu[i]) free_spu ( p_a->p_spu[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 ); if(p_a->p_page) free_page( p_a->p_page );
free_objects (p_a->p_objects); free_objects (p_a->p_objects);
}
static void dvbsub_RenderDVBSUB ( vout_thread_t *p_vout, picture_t *p_pic,
const subpicture_t *p_spu, vlc_bool_t b_crop )
{
// If we have changed the language on the fly,
if(!p_spu->p_sys) return;
if(p_spu->p_sys->b_obsolete) return;
switch (p_vout->output.i_chroma)
{
/* I420 target, no scaling */
case VLC_FOURCC('I','4','2','2'):
case VLC_FOURCC('I','4','2','0'):
case VLC_FOURCC('I','Y','U','V'):
case VLC_FOURCC('Y','V','1','2'):
// 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, VLC_FALSE );
break;
/* RV16 target, scaling */
case VLC_FOURCC('R','V','1','6'):
fprintf(stderr, "Not implemented chroma ! RV16)\n");
//RenderRV16( p_vout, p_pic, p_spu, p_spu->p_sys->b_crop );
break;
/* RV32 target, scaling */
case VLC_FOURCC('R','V','2','4'):
case VLC_FOURCC('R','V','3','2'):
fprintf(stderr, "Not implemented chroma ! RV32 \n");
//RenderRV32( p_vout, p_pic, p_spu, p_spu->p_sys->b_crop );
break;
/* NVidia overlay, no scaling */
case VLC_FOURCC('Y','U','Y','2'):
RenderYUY2( p_vout, p_pic, p_spu, VLC_FALSE );
break;
default:
msg_Err( p_vout, "unknown chroma, can't render SPU" );
break;
}
} }
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 )
const subpicture_t *p_spu, vlc_bool_t b_crop )
{ {
/* Common variables */ /* Common variables */
uint8_t *p_desty; uint8_t *p_desty;
...@@ -1162,8 +1086,8 @@ static void RenderYUY2 ( vout_thread_t *p_vout, picture_t *p_pic, ...@@ -1162,8 +1086,8 @@ 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, vlc_bool_t b_crop ) const subpicture_t *p_spu )
{ {
/* Common variables */ /* Common variables */
uint8_t *p_desty; uint8_t *p_desty;
...@@ -1224,12 +1148,59 @@ static void RenderI42x ( vout_thread_t *p_vout, picture_t *p_pic, ...@@ -1224,12 +1148,59 @@ static void RenderI42x ( vout_thread_t *p_vout, picture_t *p_pic,
} }
} }
static void dvbsub_RenderDVBSUB( vout_thread_t *p_vout, picture_t *p_pic,
const subpicture_t *p_spu )
{
/* If we have changed the language on the fly */
if( p_spu->p_sys == NULL || p_spu->p_sys->b_obsolete )
{
return;
}
switch( p_vout->output.i_chroma )
{
/* I420 target, no scaling */
case VLC_FOURCC('I','4','2','2'):
case VLC_FOURCC('I','4','2','0'):
case VLC_FOURCC('I','Y','U','V'):
case VLC_FOURCC('Y','V','1','2'):
/* 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 );
break;
/* RV16 target, scaling */
case VLC_FOURCC('R','V','1','6'):
fprintf(stderr, "Not implemented chroma ! RV16)\n");
/* RenderRV16( p_vout, p_pic, p_spu ); */
break;
/* RV32 target, scaling */
case VLC_FOURCC('R','V','2','4'):
case VLC_FOURCC('R','V','3','2'):
fprintf(stderr, "Not implemented chroma ! RV32 \n");
/* RenderRV32( p_vout, p_pic, p_spu ); */
break;
/* NVidia overlay, no scaling */
case VLC_FOURCC('Y','U','Y','2'):
RenderYUY2( p_vout, p_pic, p_spu );
break;
default:
msg_Err( p_vout, "unknown chroma, can't render SPU" );
break;
}
}
static void dvbsub_Destroy( subpicture_t *p_spu ) static void dvbsub_Destroy( subpicture_t *p_spu )
{ {
free_spu( p_spu ); free_spu( p_spu );
} }
static void dvbsub_render( dvbsub_thread_t *p_dec, dvbsub_all_t* dvbsub) static void dvbsub_render( dvbsub_all_t *dvbsub, vout_thread_t *p_vout )
{ {
dvbsub_region_t* p_region; dvbsub_region_t* p_region;
dvbsub_objectdef_t* p_objectdef; dvbsub_objectdef_t* p_objectdef;
...@@ -1240,88 +1211,91 @@ static void dvbsub_render( dvbsub_thread_t *p_dec, dvbsub_all_t* dvbsub) ...@@ -1240,88 +1211,91 @@ static void dvbsub_render( dvbsub_thread_t *p_dec, dvbsub_all_t* dvbsub)
dvbsub_rle_t* p_c; dvbsub_rle_t* p_c;
uint8_t i,j; uint8_t i,j;
j=0; j=0;
/* loop on regions */ /* loop on regions */
for(i=0; i< dvbsub->p_page->i_regions_number; i++) for( i = 0; i < dvbsub->p_page->i_regions_number; i++ )
{ {
p_region = &(dvbsub->p_page->regions[i]); p_region = &(dvbsub->p_page->regions[i]);
/* loop on objects */
for(p_objectdef = p_region->p_object; /* loop on objects */
p_objectdef != NULL; for(p_objectdef = p_region->p_object; p_objectdef != NULL; p_objectdef = p_objectdef->p_next )
p_objectdef = p_objectdef->p_next)
{
/* Look for the right object */
p_object = dvbsub->p_objects;
while((p_object!=NULL) && (p_object->i_id != p_objectdef->i_id))
{
p_object = p_object->p_next;
}
if(p_object==NULL)
{
fprintf(stderr, "Internal DvbSub decoder error\n");
return;
}
/* Allocate the render structure */
p_render = trox_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;
// if we did not recieved the CLUT yet
if ( !dvbsub->p_clut[p_region->i_clut] ) return;
/* Compute the color datas according to the appropriate CLUT */
for(p_c=p_render->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;
}
for(p_c=p_render->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 /* Look for the right object */
p_c->y=dvbsub->p_clut[p_region->i_clut]->c_4b[p_c->i_color_code].Y; p_object = dvbsub->p_objects;
p_c->cr=dvbsub->p_clut[p_region->i_clut]->c_4b[p_c->i_color_code].Cr; while((p_object!=NULL) && (p_object->i_id != p_objectdef->i_id))
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_object = p_object->p_next;
} }
if(p_object==NULL)
{
fprintf(stderr, "Internal DvbSub decoder error\n");
return;
}
/* Allocate the subpicture internal data. */ /* Allocate the render structure */
dvbsub->p_spu[j] = vout_CreateSubPicture( p_dec->p_vout, p_render = trox_malloc(sizeof(dvbsub_render_t));
MEMORY_SUBPICTURE ); p_render->i_x = p_region->i_x + p_objectdef->i_xoffset;
if( dvbsub->p_spu[j] == NULL ) p_render->i_y = p_region->i_y + p_objectdef->i_yoffset;
{ p_render->p_rle_top = p_object->topfield;
fprintf(stderr, "Unable to allocate memory ... skipping\n"); p_render->p_rle_bot = p_object->bottomfield;
return;
}
/* Set the pf_render callback */
dvbsub->p_spu[j]->pf_render = dvbsub_RenderDVBSUB;
dvbsub->p_spu[j]->p_sys = trox_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 = p_dec->bit_stream.p_pes->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_dec->p_vout, dvbsub->p_spu[j] ); // if we did not recieved the CLUT yet
j++; if ( !dvbsub->p_clut[p_region->i_clut] ) return;
}
/* Compute the color datas according to the appropriate CLUT */
for(p_c=p_render->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;
}
for(p_c=p_render->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;
}
/* Allocate the subpicture internal data. */
dvbsub->p_spu[j] = vout_CreateSubPicture( p_vout, MEMORY_SUBPICTURE );
if( dvbsub->p_spu[j] == NULL )
{
fprintf(stderr, "Unable to allocate memory ... skipping\n");
return;
}
/* Set the pf_render callback */
dvbsub->p_spu[j]->pf_render = dvbsub_RenderDVBSUB;
dvbsub->p_spu[j]->p_sys = trox_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] );
j++;
}
} }
} }
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* input_dec.c: Functions for the management of decoders * input_dec.c: Functions for the management of decoders
***************************************************************************** *****************************************************************************
* Copyright (C) 1999-2001 VideoLAN * Copyright (C) 1999-2001 VideoLAN
* $Id: input_dec.c,v 1.76 2003/11/24 00:39:02 fenrir Exp $ * $Id: input_dec.c,v 1.77 2003/11/24 02:35:50 fenrir Exp $
* *
* Authors: Christophe Massiot <massiot@via.ecp.fr> * Authors: Christophe Massiot <massiot@via.ecp.fr>
* Gildas Bazin <gbazin@netcourrier.com> * Gildas Bazin <gbazin@netcourrier.com>
...@@ -407,17 +407,25 @@ static decoder_t * CreateDecoder( input_thread_t * p_input, ...@@ -407,17 +407,25 @@ static decoder_t * CreateDecoder( input_thread_t * p_input,
p_dec->fmt_in.video.i_width = p_bih->biWidth; p_dec->fmt_in.video.i_width = p_bih->biWidth;
p_dec->fmt_in.video.i_height = p_bih->biHeight; p_dec->fmt_in.video.i_height = p_bih->biHeight;
} }
/* FIXME /* FIXME
* - 1: beurk * - 1: beurk
* - 2: I'm not sure there isn't any endian problem here ... */ * - 2: I'm not sure there isn't any endian problem here (spu)... */
if( p_es->i_cat == SPU_ES && if( p_es->i_cat == SPU_ES && p_es->p_demux_data )
( p_es->i_fourcc == VLC_FOURCC( 's', 'p', 'u', ' ' ) ||
p_es->i_fourcc == VLC_FOURCC( 's', 'p', 'u', 'b' ) ) &&
p_es->p_demux_data &&
*((uint32_t*)p_es->p_demux_data) == 0xBeef )
{ {
memcpy( p_dec->fmt_in.subs.spu.palette, if( ( p_es->i_fourcc == VLC_FOURCC( 's', 'p', 'u', ' ' ) ||
p_es->p_demux_data, 17 * 4 ); p_es->i_fourcc == VLC_FOURCC( 's', 'p', 'u', 'b' ) ) &&
*((uint32_t*)p_es->p_demux_data) == 0xBeef )
{
memcpy( p_dec->fmt_in.subs.spu.palette,
p_es->p_demux_data, 17 * 4 );
}
else if( p_es->i_fourcc == VLC_FOURCC( 'd', 'v', 'b', 's' ) )
{
dvb_spuinfo_t *p_dvbs = (dvb_spuinfo_t*)p_es->p_demux_data;
p_dec->fmt_in.subs.dvb.i_id = p_dvbs->i_id;
}
} }
p_dec->fmt_in.i_cat = p_es->i_cat; p_dec->fmt_in.i_cat = p_es->i_cat;
...@@ -464,8 +472,6 @@ static int DecoderThread( decoder_t * p_dec ) ...@@ -464,8 +472,6 @@ static int DecoderThread( decoder_t * p_dec )
/* The decoder's main loop */ /* The decoder's main loop */
while( !p_dec->b_die && !p_dec->b_error ) while( !p_dec->b_die && !p_dec->b_error )
{ {
int i_size;
if( ( p_block = block_FifoGet( p_dec->p_owner->p_fifo ) ) == NULL ) if( ( p_block = block_FifoGet( p_dec->p_owner->p_fifo ) ) == NULL )
{ {
p_dec->b_error = 1; p_dec->b_error = 1;
......
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