/* if the values we got aren't too strange, decode the data */
if( i_rle_size < i_packet_size )
{
- /* destroy the previous one */
- if( p_spu ) vout_DestroySubPicture( p_spudec->p_vout, p_spu );
-
/* allocate the subpicture.
* FIXME: we should check if the allocation failed */
p_spu = vout_CreateSubPicture( p_spudec->p_vout,
DVD_SUBPICTURE, i_rle_size );
p_spu_data = p_spu->p_data;
+ /* get display time */
+ p_spu->begin_date = p_spu->end_date
+ = DECODER_FIFO_START(p_spudec->fifo)->i_pts;
+
/* getting the RLE part */
while( i_index++ < i_rle_size )
{
{
unsigned char i_cmd;
unsigned int i_word;
+ unsigned int i_date;
/* the date */
- GetWord( i_word );
+ GetWord( i_date );
/* next offset, no next offset if == i_index-5 */
GetWord( i_word );
switch( i_cmd )
{
case 0x00:
- /* 00 (display now) */
+ /* 00 (force displaying) */
break;
case 0x01:
/* 01 (start displaying) */
- break;
+ p_spu->begin_date += (i_date * 1000000 / 80);
+ break; /* FIXME: 80 is absolutely empiric */
case 0x02:
/* 02 (stop displaying) */
- break;
+ p_spu->end_date += (i_date * 1000000 / 80);
+ break; /* FIXME: 80 is absolutely empiric */
case 0x03:
/* 03xxxx (palette) */
GetWord( i_word );
case 0x05:
/* 05xxxyyyxxxyyy (coordinates) */
i_word = GetByte( &p_spudec->bit_stream );
- p_spu->type.spu.i_x1 = (i_word << 4) | GetBits( &p_spudec->bit_stream, 4 );
+ p_spu->type.spu.i_x1 = (i_word << 4)
+ | GetBits( &p_spudec->bit_stream, 4 );
+
i_word = GetBits( &p_spudec->bit_stream, 4 );
- p_spu->type.spu.i_x2 = (i_word << 8) | GetByte( &p_spudec->bit_stream );
+ p_spu->type.spu.i_x2 = (i_word << 8)
+ | GetByte( &p_spudec->bit_stream );
+
i_word = GetByte( &p_spudec->bit_stream );
- p_spu->type.spu.i_y1 = (i_word << 4) | GetBits( &p_spudec->bit_stream, 4 );
+ p_spu->type.spu.i_y1 = (i_word << 4)
+ | GetBits( &p_spudec->bit_stream, 4 );
+
i_word = GetBits( &p_spudec->bit_stream, 4 );
- p_spu->type.spu.i_y2 = (i_word << 8) | GetByte( &p_spudec->bit_stream );
+ p_spu->type.spu.i_y2 = (i_word << 8)
+ | GetByte( &p_spudec->bit_stream );
+
i_index += 6;
break;
case 0x06:
{
p_vout->p_picture[i_index].i_type = EMPTY_PICTURE;
p_vout->p_picture[i_index].i_status = FREE_PICTURE;
+ }
+ for( i_index = 0; i_index < VOUT_MAX_SUBPICTURES; i_index++)
+ {
p_vout->p_subpicture[i_index].i_type = EMPTY_SUBPICTURE;
p_vout->p_subpicture[i_index].i_status= FREE_SUBPICTURE;
}
/*
* Look for an empty place
*/
- for( i_subpic = 0; i_subpic < VOUT_MAX_PICTURES; i_subpic++ )
+ for( i_subpic = 0; i_subpic < VOUT_MAX_SUBPICTURES; i_subpic++ )
{
if( p_vout->p_subpicture[i_subpic].i_status == DESTROYED_SUBPICTURE )
{
#if 1
if( display_date < current_date && i_trash_count > 4 )
{
- /* Picture is late: it will be destroyed and the thread will sleep and
- * go to next picture */
+ /* Picture is late: it will be destroyed and the thread
+ * will sleep and go to next picture */
vlc_mutex_lock( &p_vout->picture_lock );
if( p_pic->i_refcount )
/*
* Find the subpictures to display - this operation does not need
* lock, since only READY_SUBPICTURE are handled. If no picture
- * has been selected, display_date will depend on the subpicture
+ * has been selected, display_date will depend on the subpicture.
+ * We get an easily parsable chained list of subpictures which
+ * ends with NULL since p_subpic was initialized to NULL.
*/
- /* FIXME: we should find *all* subpictures to display, and
- * check their displaying date as well */
- for( i_index = 0; i_index < VOUT_MAX_PICTURES; i_index++ )
+ for( i_index = 0; i_index < VOUT_MAX_SUBPICTURES; i_index++ )
{
if( p_vout->p_subpicture[i_index].i_status == READY_SUBPICTURE )
{
+ p_vout->p_subpicture[i_index].p_next = p_subpic;
p_subpic = &p_vout->p_subpicture[i_index];
- break;
}
}
{
free( p_vout->p_picture[i_index].p_data );
}
+ }
+ for( i_index = 0; i_index < VOUT_MAX_SUBPICTURES; i_index++ )
+ {
if( p_vout->p_subpicture[i_index].i_status != FREE_SUBPICTURE )
{
free( p_vout->p_subpicture[i_index].p_data );
p_vout_font_t p_font; /* text font */
int i_width, i_height; /* subpicture dimensions */
- switch( p_subpic->i_type )
+ while( p_subpic != NULL )
{
- case DVD_SUBPICTURE: /* DVD subpicture unit */
- vout_RenderSPU( p_subpic->p_data, p_subpic->type.spu.i_offset,
- p_subpic->type.spu.i_x1, p_subpic->type.spu.i_y1,
- p_vout->p_buffer[ p_vout->i_buffer_index ].p_data,
- p_vout->i_bytes_per_pixel, p_vout->i_bytes_per_line );
- break;
- case TEXT_SUBPICTURE: /* single line text */
- /* Select default font if not specified */
- p_font = p_subpic->type.text.p_font;
- if( p_font == NULL )
+ switch( p_subpic->i_type )
{
- p_font = p_vout->p_default_font;
- }
+ case DVD_SUBPICTURE: /* DVD subpicture unit */
+ /* test if the picture really has to be displayed */
+ if( mdate() < p_subpic->begin_date )
+ {
+ break;
+ }
+ if( mdate() > p_subpic->end_date )
+ {
+ /* too late, destroying the subpic */
+ vout_DestroySubPicture( p_vout, p_subpic );
+ printf( "destroying subpicture\n" );
+ break;
+ }
+ vout_RenderSPU( p_subpic->p_data, p_subpic->type.spu.i_offset,
+ p_subpic->type.spu.i_x1, p_subpic->type.spu.i_y1,
+ p_vout->p_buffer[ p_vout->i_buffer_index ].p_data,
+ p_vout->i_bytes_per_pixel,
+ p_vout->i_bytes_per_line );
+ break;
+ case TEXT_SUBPICTURE: /* single line text */
+ /* Select default font if not specified */
+ p_font = p_subpic->type.text.p_font;
+ if( p_font == NULL )
+ {
+ p_font = p_vout->p_default_font;
+ }
- /* Compute text size (width and height fields are ignored)
- * and print it */
- vout_TextSize( p_font, p_subpic->type.text.i_style, p_subpic->p_data, &i_width, &i_height );
- if( !Align( p_vout, &p_subpic->i_x, &p_subpic->i_y, i_width, i_height,
- p_subpic->i_horizontal_align, p_subpic->i_vertical_align ) )
- {
- vout_Print( p_font, p_vout->p_buffer[ p_vout->i_buffer_index ].p_data +
- p_subpic->i_x * p_vout->i_bytes_per_pixel +
- p_subpic->i_y * p_vout->i_bytes_per_line,
- p_vout->i_bytes_per_pixel, p_vout->i_bytes_per_line,
- p_subpic->type.text.i_char_color, p_subpic->type.text.i_border_color,
- p_subpic->type.text.i_bg_color, p_subpic->type.text.i_style,
- p_subpic->p_data );
- SetBufferArea( p_vout, p_subpic->i_x, p_subpic->i_y, i_width, i_height );
- }
- break;
+ /* Compute text size (width and height fields are ignored)
+ * and print it */
+ vout_TextSize( p_font, p_subpic->type.text.i_style,
+ p_subpic->p_data, &i_width, &i_height );
+ if( !Align( p_vout, &p_subpic->i_x, &p_subpic->i_y,
+ i_width, i_height, p_subpic->i_horizontal_align,
+ p_subpic->i_vertical_align ) )
+ {
+ vout_Print( p_font,
+ p_vout->p_buffer[ p_vout->i_buffer_index ].p_data +
+ p_subpic->i_x * p_vout->i_bytes_per_pixel +
+ p_subpic->i_y * p_vout->i_bytes_per_line,
+ p_vout->i_bytes_per_pixel, p_vout->i_bytes_per_line,
+ p_subpic->type.text.i_char_color,
+ p_subpic->type.text.i_border_color,
+ p_subpic->type.text.i_bg_color,
+ p_subpic->type.text.i_style, p_subpic->p_data );
+ SetBufferArea( p_vout, p_subpic->i_x, p_subpic->i_y,
+ i_width, i_height );
+ }
+ break;
#ifdef DEBUG
- default:
- intf_DbgMsg("error: unknown subpicture %p type %d\n", p_subpic, p_subpic->i_type );
+ default:
+ intf_DbgMsg( "error: unknown subpicture %p type %d\n",
+ p_subpic, p_subpic->i_type );
#endif
+ }
+
+ p_subpic = p_subpic->p_next;
}
}
} spu_t;
static int NewLine ( spu_t *p_spu, int *i_id );
-static int PutPixel ( spu_t *p_spu, int len, u8 color );
/* i = get_nibble(); */
#define GET_NIBBLE( i ) \
int i_code = 0x00;
int i_next = 0;
int i_id = 0;
+ int i_color;
+ static int p_palette[4] = { 0x0000, 0xffff, 0x5555, 0x0000 };
+
boolean_t b_aligned = 1;
byte_t *p_from[2];
spu_t spu;
spu.height = 576;
spu.p_data = p_pic + i_x * i_bytes_per_pixel + i_y * i_bytes_per_line;
- while( p_from[0] < p_data + p_offset[1] + 2 )
+ while( p_from[0] < p_data + p_offset[1] )
{
GET_NIBBLE( i_code );
if( i_code >= 0x04 )
{
found_code:
- if( PutPixel( &spu, i_code >> 2, i_code & 3 ) < 0 )
+
+ if( ((i_code >> 2) + spu.x + spu.y * spu.width)
+ > spu.height * spu.width )
+ {
+ intf_DbgMsg ( "video_spu: invalid draw request ! %d %d\n",
+ i_code >> 2, spu.height * spu.width
+ - ( (i_code >> 2) + spu.x
+ + spu.y * spu.width ) );
return;
+ }
+ else
+ {
+ if( (i_color = i_code & 0x3) )
+ {
+ u8 *p_target = &spu.p_data[ 2 *
+ ( spu.x + spu.y * spu.width ) ];
+ memset( p_target, p_palette[i_color], 2 * (i_code >> 2) );
+ }
+ spu.x += i_code >> 2;
+ }
if( spu.x >= spu.width )
{
static int NewLine( spu_t *p_spu, int *i_id )
{
- int i_ret = PutPixel( p_spu, p_spu->width - p_spu->x, 0 );
+ *i_id = 1 - *i_id;
p_spu->x = 0;
p_spu->y++;
- *i_id = 1 - *i_id;
- return i_ret;
-}
-
-static int PutPixel ( spu_t *p_spu, int i_len, u8 i_color )
-{
- //static int p_palette[4] = { 0x0000, 0xfef8, 0x7777, 0xffff };
- static int p_palette[4] = { 0x0000, 0xffff, 0x5555, 0x0000 };
-
- if( (i_len + p_spu->x + p_spu->y * p_spu->width)
- > p_spu->height * p_spu->width )
- {
- intf_DbgMsg ( "video_spu: trying to draw beyond memory area! %d %d\n",
- i_len, p_spu->height * p_spu->width
- - ( i_len + p_spu->x + p_spu->y * p_spu->width) );
- p_spu->x += i_len;
- return -1;
- }
- else
- {
-
- if( i_color > 0x0f )
- intf_DbgMsg( "video_spu: invalid color\n" );
-
- if( i_color )
- {
- u8 *p_target
- = &p_spu->p_data[2 * ( p_spu->x + p_spu->y * p_spu->width ) ];
-
- memset( p_target, p_palette[i_color], 2 * i_len );
- }
- p_spu->x += i_len;
- }
+ return( p_spu->width - p_spu->y );
- return 0;
}