Commit a77d5a3e authored by Sam Hocevar's avatar Sam Hocevar

  * Additional optimizations to the subtitle decoder
  * The GGI video output should now be faster. Also, right-mouse-clicking
    works in GGI mode as well.
parent a20df577
...@@ -136,6 +136,7 @@ int vout_Create( vout_thread_t *p_vout ) ...@@ -136,6 +136,7 @@ int vout_Create( vout_thread_t *p_vout )
free( p_vout->p_sys ); free( p_vout->p_sys );
return( 1 ); return( 1 );
} }
return( 0 ); return( 0 );
} }
...@@ -146,13 +147,23 @@ int vout_Create( vout_thread_t *p_vout ) ...@@ -146,13 +147,23 @@ int vout_Create( vout_thread_t *p_vout )
*****************************************************************************/ *****************************************************************************/
int vout_Init( vout_thread_t *p_vout ) int vout_Init( vout_thread_t *p_vout )
{ {
#define p_b p_vout->p_sys->p_buffer
/* Acquire first buffer */ /* Acquire first buffer */
if( p_vout->p_sys->b_must_acquire ) if( p_vout->p_sys->b_must_acquire )
{ {
ggiResourceAcquire( p_vout->p_sys->p_buffer[ p_vout->i_buffer_index ]->resource, GGI_ACTYPE_WRITE ); ggiResourceAcquire( p_b[ p_vout->i_buffer_index ]->resource,
GGI_ACTYPE_WRITE );
} }
/* Listen to the keyboard and the mouse buttons */
ggiSetEventMask( p_vout->p_sys->p_display,
emKeyboard | emPtrButtonPress | emPtrButtonRelease );
/* Set asynchronous display mode -- usually quite faster */
ggiAddFlags( p_vout->p_sys->p_display, GGIFLAG_ASYNC );
return( 0 ); return( 0 );
#undef p_b
} }
/***************************************************************************** /*****************************************************************************
...@@ -162,11 +173,13 @@ int vout_Init( vout_thread_t *p_vout ) ...@@ -162,11 +173,13 @@ int vout_Init( vout_thread_t *p_vout )
*****************************************************************************/ *****************************************************************************/
void vout_End( vout_thread_t *p_vout ) void vout_End( vout_thread_t *p_vout )
{ {
#define p_b p_vout->p_sys->p_buffer
/* Release buffer */ /* Release buffer */
if( p_vout->p_sys->b_must_acquire ) if( p_vout->p_sys->b_must_acquire )
{ {
ggiResourceRelease( p_vout->p_sys->p_buffer[ p_vout->i_buffer_index ]->resource ); ggiResourceRelease( p_b[ p_vout->i_buffer_index ]->resource );
} }
#undef p_b
} }
/***************************************************************************** /*****************************************************************************
...@@ -189,15 +202,27 @@ void vout_Destroy( vout_thread_t *p_vout ) ...@@ -189,15 +202,27 @@ void vout_Destroy( vout_thread_t *p_vout )
*****************************************************************************/ *****************************************************************************/
int vout_Manage( vout_thread_t *p_vout ) int vout_Manage( vout_thread_t *p_vout )
{ {
int i_key; /* unicode key */ struct timeval tv = { 0, 1000 }; /* 1 millisecond */
gii_event_mask mask;
gii_event event;
mask = emKeyboard | emPtrButtonPress | emPtrButtonRelease;
ggiEventPoll( p_vout->p_sys->p_display, mask, &tv );
/* For all events in queue */ while( ggiEventsQueued( p_vout->p_sys->p_display, mask) )
while( ggiKbhit( p_vout->p_sys->p_display ) )
{ {
i_key = ggiGetc( p_vout->p_sys->p_display ); ggiEventRead( p_vout->p_sys->p_display, &event, mask);
switch( i_key )
switch( event.any.type )
{
case evKeyRelease:
switch( event.key.sym )
{ {
case 'q': case 'q':
case 'Q':
case GIIUC_Escape:
/* FIXME pass message ! */ /* FIXME pass message ! */
p_main->p_intf->b_die = 1; p_main->p_intf->b_die = 1;
break; break;
...@@ -205,6 +230,21 @@ int vout_Manage( vout_thread_t *p_vout ) ...@@ -205,6 +230,21 @@ int vout_Manage( vout_thread_t *p_vout )
default: default:
break; break;
} }
break;
case evPtrButtonRelease:
switch( event.pbutton.button )
{
case GII_PBUTTON_RIGHT:
/* FIXME: need locking ! */
p_main->p_intf->b_menu_change = 1;
break;
}
default:
}
} }
return( 0 ); return( 0 );
...@@ -218,23 +258,27 @@ int vout_Manage( vout_thread_t *p_vout ) ...@@ -218,23 +258,27 @@ int vout_Manage( vout_thread_t *p_vout )
*****************************************************************************/ *****************************************************************************/
void vout_Display( vout_thread_t *p_vout ) void vout_Display( vout_thread_t *p_vout )
{ {
#define p_b p_vout->p_sys->p_buffer
/* Change display frame */ /* Change display frame */
if( p_vout->p_sys->b_must_acquire ) if( p_vout->p_sys->b_must_acquire )
{ {
ggiResourceRelease( p_vout->p_sys->p_buffer[ p_vout->i_buffer_index ]->resource ); ggiResourceRelease( p_b[ p_vout->i_buffer_index ]->resource );
} }
ggiFlush( p_vout->p_sys->p_display ); /* XXX?? */
ggiSetDisplayFrame( p_vout->p_sys->p_display, ggiSetDisplayFrame( p_vout->p_sys->p_display,
p_vout->p_sys->p_buffer[ p_vout->i_buffer_index ]->frame ); p_b[ p_vout->i_buffer_index ]->frame );
/* Swap buffers and change write frame */ /* Swap buffers and change write frame */
if( p_vout->p_sys->b_must_acquire ) if( p_vout->p_sys->b_must_acquire )
{ {
ggiResourceAcquire( p_vout->p_sys->p_buffer[ (p_vout->i_buffer_index + 1) & 1]->resource, ggiResourceAcquire( p_b[ (p_vout->i_buffer_index + 1) & 1]->resource,
GGI_ACTYPE_WRITE ); GGI_ACTYPE_WRITE );
} }
ggiSetWriteFrame( p_vout->p_sys->p_display, ggiSetWriteFrame( p_vout->p_sys->p_display,
p_vout->p_sys->p_buffer[ (p_vout->i_buffer_index + 1) & 1]->frame ); p_b[ (p_vout->i_buffer_index + 1) & 1]->frame );
/* Flush the output so that it actually displays */
ggiFlush( p_vout->p_sys->p_display );
#undef p_b
} }
/* following functions are local */ /* following functions are local */
...@@ -247,6 +291,7 @@ void vout_Display( vout_thread_t *p_vout ) ...@@ -247,6 +291,7 @@ void vout_Display( vout_thread_t *p_vout )
*****************************************************************************/ *****************************************************************************/
static int GGIOpenDisplay( vout_thread_t *p_vout ) static int GGIOpenDisplay( vout_thread_t *p_vout )
{ {
#define p_b p_vout->p_sys->p_buffer
ggi_mode mode; /* mode descriptor */ ggi_mode mode; /* mode descriptor */
ggi_color col_fg; /* foreground color */ ggi_color col_fg; /* foreground color */
ggi_color col_bg; /* background color */ ggi_color col_bg; /* background color */
...@@ -287,8 +332,7 @@ static int GGIOpenDisplay( vout_thread_t *p_vout ) ...@@ -287,8 +332,7 @@ static int GGIOpenDisplay( vout_thread_t *p_vout )
mode.dpp.y = GGI_AUTO; mode.dpp.y = GGI_AUTO;
ggiCheckMode( p_vout->p_sys->p_display, &mode ); ggiCheckMode( p_vout->p_sys->p_display, &mode );
/* Check that returned mode has some minimum properties */ /* FIXME: Check that returned mode has some minimum properties */
/* XXX?? */
/* Set mode */ /* Set mode */
if( ggiSetMode( p_vout->p_sys->p_display, &mode ) ) if( ggiSetMode( p_vout->p_sys->p_display, &mode ) )
...@@ -305,8 +349,9 @@ static int GGIOpenDisplay( vout_thread_t *p_vout ) ...@@ -305,8 +349,9 @@ static int GGIOpenDisplay( vout_thread_t *p_vout )
{ {
/* Get buffer address */ /* Get buffer address */
p_vout->p_sys->p_buffer[ i_index ] = p_vout->p_sys->p_buffer[ i_index ] =
(ggi_directbuffer *)ggiDBGetBuffer( p_vout->p_sys->p_display, i_index ); (ggi_directbuffer *)ggiDBGetBuffer( p_vout->p_sys->p_display,
if( p_vout->p_sys->p_buffer[ i_index ] == NULL ) i_index );
if( p_b[ i_index ] == NULL )
{ {
intf_ErrMsg( "vout error: double buffering is not possible" ); intf_ErrMsg( "vout error: double buffering is not possible" );
ggiClose( p_vout->p_sys->p_display ); ggiClose( p_vout->p_sys->p_display );
...@@ -315,11 +360,11 @@ static int GGIOpenDisplay( vout_thread_t *p_vout ) ...@@ -315,11 +360,11 @@ static int GGIOpenDisplay( vout_thread_t *p_vout )
} }
/* Check buffer properties */ /* Check buffer properties */
if( ! (p_vout->p_sys->p_buffer[ i_index ]->type & GGI_DB_SIMPLE_PLB) || if( ! ( p_b[ i_index ]->type & GGI_DB_SIMPLE_PLB )
(p_vout->p_sys->p_buffer[ i_index ]->page_size != 0) || || ( p_b[ i_index ]->page_size != 0 )
(p_vout->p_sys->p_buffer[ i_index ]->write == NULL ) || || ( p_b[ i_index ]->write == NULL )
(p_vout->p_sys->p_buffer[ i_index ]->noaccess != 0) || || ( p_b[ i_index ]->noaccess != 0 )
(p_vout->p_sys->p_buffer[ i_index ]->align != 0) ) || ( p_b[ i_index ]->align != 0 ) )
{ {
intf_ErrMsg( "vout error: incorrect video memory type" ); intf_ErrMsg( "vout error: incorrect video memory type" );
ggiClose( p_vout->p_sys->p_display ); ggiClose( p_vout->p_sys->p_display );
...@@ -328,17 +373,16 @@ static int GGIOpenDisplay( vout_thread_t *p_vout ) ...@@ -328,17 +373,16 @@ static int GGIOpenDisplay( vout_thread_t *p_vout )
} }
/* Check if buffer needs to be acquired before write */ /* Check if buffer needs to be acquired before write */
if( ggiResourceMustAcquire( p_vout->p_sys->p_buffer[ i_index ]->resource ) ) if( ggiResourceMustAcquire( p_b[ i_index ]->resource ) )
{ {
p_vout->p_sys->b_must_acquire = 1; p_vout->p_sys->b_must_acquire = 1;
} }
} }
#ifdef DEBUG
if( p_vout->p_sys->b_must_acquire ) if( p_vout->p_sys->b_must_acquire )
{ {
intf_DbgMsg("buffers must be acquired"); intf_DbgMsg("buffers must be acquired");
} }
#endif
/* Set graphic context colors */ /* Set graphic context colors */
col_fg.r = col_fg.g = col_fg.b = -1; col_fg.r = col_fg.g = col_fg.b = -1;
...@@ -367,18 +411,20 @@ static int GGIOpenDisplay( vout_thread_t *p_vout ) ...@@ -367,18 +411,20 @@ static int GGIOpenDisplay( vout_thread_t *p_vout )
/* Set thread information */ /* Set thread information */
p_vout->i_width = mode.visible.x; p_vout->i_width = mode.visible.x;
p_vout->i_height = mode.visible.y; p_vout->i_height = mode.visible.y;
p_vout->i_bytes_per_line = p_vout->p_sys->p_buffer[ 0 ]->buffer.plb.stride; p_vout->i_bytes_per_line = p_b[ 0 ]->buffer.plb.stride;
p_vout->i_screen_depth = p_vout->p_sys->p_buffer[ 0 ]->buffer.plb.pixelformat->depth; p_vout->i_screen_depth = p_b[ 0 ]->buffer.plb.pixelformat->depth;
p_vout->i_bytes_per_pixel = p_vout->p_sys->p_buffer[ 0 ]->buffer.plb.pixelformat->size / 8; p_vout->i_bytes_per_pixel = p_b[ 0 ]->buffer.plb.pixelformat->size / 8;
p_vout->i_red_mask = p_vout->p_sys->p_buffer[ 0 ]->buffer.plb.pixelformat->red_mask; p_vout->i_red_mask = p_b[ 0 ]->buffer.plb.pixelformat->red_mask;
p_vout->i_green_mask = p_vout->p_sys->p_buffer[ 0 ]->buffer.plb.pixelformat->green_mask; p_vout->i_green_mask = p_b[ 0 ]->buffer.plb.pixelformat->green_mask;
p_vout->i_blue_mask = p_vout->p_sys->p_buffer[ 0 ]->buffer.plb.pixelformat->blue_mask; p_vout->i_blue_mask = p_b[ 0 ]->buffer.plb.pixelformat->blue_mask;
/* FIXME: palette in 8bpp ?? */
/* FIXME: set palette in 8bpp */
/* Set and initialize buffers */ /* Set and initialize buffers */
vout_SetBuffers( p_vout, p_vout->p_sys->p_buffer[ 0 ]->write, p_vout->p_sys->p_buffer[ 1 ]->write ); vout_SetBuffers( p_vout, p_b[ 0 ]->write, p_b[ 1 ]->write );
return( 0 ); return( 0 );
#undef p_b
} }
/***************************************************************************** /*****************************************************************************
......
...@@ -213,7 +213,7 @@ static int SyncPacket( spudec_thread_t *p_spudec ) ...@@ -213,7 +213,7 @@ static int SyncPacket( spudec_thread_t *p_spudec )
p_spudec->i_spu_size = GetBits( &p_spudec->bit_stream, 16 ); p_spudec->i_spu_size = GetBits( &p_spudec->bit_stream, 16 );
/* The RLE stuff size (remove 4 because we just read 32 bits) */ /* The RLE stuff size (remove 4 because we just read 32 bits) */
p_spudec->i_rle_size = GetBits( &p_spudec->bit_stream, 16 ) - 4; p_spudec->i_rle_size = ShowBits( &p_spudec->bit_stream, 16 ) - 4;
/* If the values we got are a bit strange, skip packet */ /* If the values we got are a bit strange, skip packet */
if( p_spudec->i_rle_size >= p_spudec->i_spu_size ) if( p_spudec->i_rle_size >= p_spudec->i_spu_size )
...@@ -221,6 +221,8 @@ static int SyncPacket( spudec_thread_t *p_spudec ) ...@@ -221,6 +221,8 @@ static int SyncPacket( spudec_thread_t *p_spudec )
return( 1 ); return( 1 );
} }
RemoveBits( &p_spudec->bit_stream, 16 );
return( 0 ); return( 0 );
} }
...@@ -233,7 +235,7 @@ static int SyncPacket( spudec_thread_t *p_spudec ) ...@@ -233,7 +235,7 @@ static int SyncPacket( spudec_thread_t *p_spudec )
static void ParsePacket( spudec_thread_t *p_spudec ) static void ParsePacket( spudec_thread_t *p_spudec )
{ {
subpicture_t * p_spu; subpicture_t * p_spu;
u8 * p_source; u8 * p_src;
/* We cannot display a subpicture with no date */ /* We cannot display a subpicture with no date */
if( DECODER_FIFO_START(*p_spudec->p_fifo)->i_pts == 0 ) if( DECODER_FIFO_START(*p_spudec->p_fifo)->i_pts == 0 )
...@@ -246,8 +248,8 @@ static void ParsePacket( spudec_thread_t *p_spudec ) ...@@ -246,8 +248,8 @@ static void ParsePacket( spudec_thread_t *p_spudec )
p_spudec->i_rle_size * 4 ); p_spudec->i_rle_size * 4 );
/* Rationale for the "p_spudec->i_rle_size * 4": we are going to /* Rationale for the "p_spudec->i_rle_size * 4": we are going to
* expand the RLE stuff so that we won't need to read nibbles later * expand the RLE stuff so that we won't need to read nibbles later
* on. This will speed things up a lot. Plus, we won't need to do * on. This will speed things up a lot. Plus, we'll only need to do
* this stupid interlacing stuff. */ * this stupid interlacing stuff once. */
if( p_spu == NULL ) if( p_spu == NULL )
{ {
...@@ -259,17 +261,17 @@ static void ParsePacket( spudec_thread_t *p_spudec ) ...@@ -259,17 +261,17 @@ static void ParsePacket( spudec_thread_t *p_spudec )
= DECODER_FIFO_START(*p_spudec->p_fifo)->i_pts; = DECODER_FIFO_START(*p_spudec->p_fifo)->i_pts;
/* Allocate the temporary buffer we will parse */ /* Allocate the temporary buffer we will parse */
p_source = malloc( p_spudec->i_rle_size ); p_src = malloc( p_spudec->i_rle_size );
if( p_source == NULL ) if( p_src == NULL )
{ {
intf_ErrMsg( "spudec error: could not allocate p_source" ); intf_ErrMsg( "spudec error: could not allocate p_src" );
vout_DestroySubPicture( p_spudec->p_vout, p_spu ); vout_DestroySubPicture( p_spudec->p_vout, p_spu );
return; return;
} }
/* Get RLE data */ /* Get RLE data */
GetChunk( &p_spudec->bit_stream, p_source, p_spudec->i_rle_size ); GetChunk( &p_spudec->bit_stream, p_src, p_spudec->i_rle_size );
#if 0 #if 0
/* Dump the subtitle info */ /* Dump the subtitle info */
...@@ -280,29 +282,29 @@ static void ParsePacket( spudec_thread_t *p_spudec ) ...@@ -280,29 +282,29 @@ static void ParsePacket( spudec_thread_t *p_spudec )
if( ParseControlSequences( p_spudec, p_spu ) ) if( ParseControlSequences( p_spudec, p_spu ) )
{ {
/* There was a parse error, delete the subpicture */ /* There was a parse error, delete the subpicture */
free( p_source ); free( p_src );
vout_DestroySubPicture( p_spudec->p_vout, p_spu ); vout_DestroySubPicture( p_spudec->p_vout, p_spu );
return; return;
} }
intf_WarnMsg( 1, "spudec: got a valid %ix%i subtitle at (%i,%i), " if( ParseRLE( p_src, p_spu ) )
"RLE offsets: 0x%x 0x%x",
p_spu->i_width, p_spu->i_height, p_spu->i_x, p_spu->i_y,
p_spu->type.spu.i_offset[0], p_spu->type.spu.i_offset[1] );
if( ParseRLE( p_source, p_spu ) )
{ {
/* There was a parse error, delete the subpicture */ /* There was a parse error, delete the subpicture */
free( p_source ); free( p_src );
vout_DestroySubPicture( p_spudec->p_vout, p_spu ); vout_DestroySubPicture( p_spudec->p_vout, p_spu );
return; return;
} }
intf_WarnMsg( 1, "spudec: got a valid %ix%i subtitle at (%i,%i), "
"RLE offsets: 0x%x 0x%x",
p_spu->i_width, p_spu->i_height, p_spu->i_x, p_spu->i_y,
p_spu->type.spu.i_offset[0], p_spu->type.spu.i_offset[1] );
/* SPU is finished - we can tell the video output to display it */ /* SPU is finished - we can tell the video output to display it */
vout_DisplaySubPicture( p_spudec->p_vout, p_spu ); vout_DisplaySubPicture( p_spudec->p_vout, p_spu );
/* Clean up */ /* Clean up */
free( p_source ); free( p_src );
} }
/***************************************************************************** /*****************************************************************************
...@@ -355,14 +357,14 @@ static int ParseControlSequences( spudec_thread_t *p_spudec, ...@@ -355,14 +357,14 @@ static int ParseControlSequences( spudec_thread_t *p_spudec,
case SPU_CMD_START_DISPLAY: case SPU_CMD_START_DISPLAY:
/* 01 (start displaying) */ /* 01 (start displaying) */
p_spu->begin_date += ( i_date * 12000 ); p_spu->begin_date += ( i_date * 11000 );
break; break;
case SPU_CMD_STOP_DISPLAY: case SPU_CMD_STOP_DISPLAY:
/* 02 (stop displaying) */ /* 02 (stop displaying) */
p_spu->end_date += ( i_date * 12000 ); p_spu->end_date += ( i_date * 11000 );
break; break;
...@@ -484,111 +486,91 @@ static int ParseControlSequences( spudec_thread_t *p_spudec, ...@@ -484,111 +486,91 @@ static int ParseControlSequences( spudec_thread_t *p_spudec,
* convenient structure for later decoding. For more information on the * convenient structure for later decoding. For more information on the
* subtitles format, see http://sam.zoy.org/doc/dvd/subtitles/index.html * subtitles format, see http://sam.zoy.org/doc/dvd/subtitles/index.html
*****************************************************************************/ *****************************************************************************/
static int ParseRLE( u8 *p_source, subpicture_t * p_spu ) static int ParseRLE( u8 *p_src, subpicture_t * p_spu )
{ {
int i_code; unsigned int i_code;
int i_id = 0; unsigned int i_id = 0;
int i_width = p_spu->i_width; unsigned int i_width = p_spu->i_width;
int i_height = p_spu->i_height; unsigned int i_height = p_spu->i_height;
int i_x = 0, i_y = 0; unsigned int i_x, i_y;
u16 *p_dest = (u16 *)p_spu->p_data; u16 *p_dest = (u16 *)p_spu->p_data;
int pi_index[2];
pi_index[0] = p_spu->type.spu.i_offset[0] << 1; /* The subtitles are interlaced, we need two offsets */
pi_index[1] = p_spu->type.spu.i_offset[1] << 1; unsigned int pi_table[2];
unsigned int *pi_offset;
pi_table[0] = p_spu->type.spu.i_offset[0] << 1;
pi_table[1] = p_spu->type.spu.i_offset[1] << 1;
while( i_y < i_height ) for( i_y = 0 ; i_y < i_height ; i_y++ )
{ {
i_code = GetNibble( p_source, pi_index + i_id ); pi_offset = pi_table + i_id;
if( i_code >= 0x04 ) for( i_x = 0 ; i_x < i_width ; i_x += i_code >> 2 )
{ {
found_code: i_code = AddNibble( 0, p_src, pi_offset );
if( ((i_code >> 2) + i_x + i_y * i_width) > i_height * i_width ) if( i_code < 0x04 )
{ {
intf_ErrMsg( "spudec error: out of bounds, %i at (%i,%i) is " i_code = AddNibble( i_code, p_src, pi_offset );
"out of %ix%i",
i_code >> 2, i_x, i_y, i_width, i_height);
return( 1 );
}
else
{
/* Store the code */
*p_dest++ = i_code;
i_x += i_code >> 2; if( i_code < 0x10 )
} {
i_code = AddNibble( i_code, p_src, pi_offset );
if( i_x > i_width ) if( i_code < 0x040 )
{ {
intf_ErrMsg( "spudec error: i_x overflowed, %i > %i", i_code = AddNibble( i_code, p_src, pi_offset );
i_x, i_width );
return( 1 );
}
if( i_x == i_width ) if( i_code < 0x0100 )
{ {
/* byte-align the stream */ /* If the 14 first bits are set to 0, then it's a
if( pi_index[i_id] & 0x1 ) * new line. We emulate it. */
if( i_code < 0x0004 )
{ {
pi_index[i_id]++; i_code |= ( i_width - i_x ) << 2;
} }
else
i_id = ~i_id & 0x1;
i_y++;
i_x = 0;
if( i_y > i_height )
{ {
intf_ErrMsg( "spudec error: i_y overflowed at EOL, " /* We have a boo boo ! */
"%i > %i", i_y, i_height ); intf_ErrMsg( "spudec error: unknown code %.4x",
i_code );
return( 1 ); return( 1 );
} }
} }
continue;
} }
}
i_code = ( i_code << 4 ) + GetNibble( p_source, pi_index + i_id );
/* 00 11 xx cc */
if( i_code >= 0x10 )
{
/* 00 01 xx cc */
goto found_code;
} }
i_code = ( i_code << 4 ) + GetNibble( p_source, pi_index + i_id ); if( ( (i_code >> 2) + i_x + i_y * i_width ) > i_height * i_width )
/* 00 00 11 xx xx cc */
if( i_code >= 0x040 )
{ {
goto found_code; /* 00 00 01 xx xx cc */ intf_ErrMsg( "spudec error: out of bounds, %i at (%i,%i) is "
"out of %ix%i",
i_code >> 2, i_x, i_y, i_width, i_height);
return( 1 );
} }
i_code = ( i_code << 4 ) + GetNibble( p_source, pi_index + i_id ); /* We got a valid code, store it */
*p_dest++ = i_code;
if( i_code >= 0x0100 ) /* 00 00 00 11 xx xx xx cc */
{
goto found_code; /* 00 00 00 01 xx xx xx cc */
} }
if( i_code & ~0x0003 ) /* Check that we didn't go too far */
if( i_x > i_width )
{ {
/* We have a boo boo ! */ intf_ErrMsg( "spudec error: i_x overflowed, %i > %i",
intf_ErrMsg( "spudec error: unknown code 0x%.4x", i_code ); i_x, i_width );
return( 1 ); return( 1 );
} }
else
/* Byte-align the stream */
if( *pi_offset & 0x1 )
{ {
/* If the 14 first bits are 0, then it's a new line */ (*pi_offset)++;
i_code |= ( i_width - i_x ) << 2;
goto found_code;
} }
/* Swap fields */
i_id = ~i_id & 0x1;
} }
/* FIXME: we shouldn't need these padding bytes */ /* FIXME: we shouldn't need these padding bytes */
......
...@@ -65,17 +65,18 @@ typedef struct spudec_thread_s ...@@ -65,17 +65,18 @@ typedef struct spudec_thread_s
#define SPU_CMD_END 0xff #define SPU_CMD_END 0xff
/***************************************************************************** /*****************************************************************************
* GetNibble: read a nibble from a source packet. * AddNibble: read a nibble from a source packet and add it to our integer.
*****************************************************************************/ *****************************************************************************/
static __inline__ u8 GetNibble( u8 *p_source, int *pi_index ) static __inline__ unsigned int AddNibble( unsigned int i_code,
u8 *p_src, int *pi_index )
{ {
if( *pi_index & 0x1 ) if( *pi_index & 0x1 )
{ {
return( p_source[(*pi_index)++ >> 1] & 0xf ); return( i_code << 4 | ( p_src[(*pi_index)++ >> 1] & 0xf ) );
} }
else else
{ {
return( p_source[(*pi_index)++ >> 1] >> 4 ); return( i_code << 4 | p_src[(*pi_index)++ >> 1] >> 4 );
} }
} }
......
...@@ -4,7 +4,6 @@ ...@@ -4,7 +4,6 @@
* Copyright (C) 1999, 2000 VideoLAN * Copyright (C) 1999, 2000 VideoLAN
* *
* Authors: Samuel Hocevar <sam@zoy.org> * Authors: Samuel Hocevar <sam@zoy.org>
* Henri Fallon <henri@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
...@@ -61,7 +60,7 @@ void vout_RenderSPU( vout_buffer_t *p_buffer, subpicture_t *p_spu, ...@@ -61,7 +60,7 @@ void vout_RenderSPU( vout_buffer_t *p_buffer, subpicture_t *p_spu,
int i_width = p_spu->i_width * i_xscale; int i_width = p_spu->i_width * i_xscale;
int i_height = p_spu->i_height * i_yscale; int i_height = p_spu->i_height * i_yscale;
int i_x = 0, i_y = 0; int i_x = 0, i_y = 0, i_ytmp, i_yreal, i_ynext;
u8 *p_dest = p_buffer->p_data u8 *p_dest = p_buffer->p_data
/* Add the picture coordinates and the SPU coordinates */ /* Add the picture coordinates and the SPU coordinates */
...@@ -71,7 +70,19 @@ void vout_RenderSPU( vout_buffer_t *p_buffer, subpicture_t *p_spu, ...@@ -71,7 +70,19 @@ void vout_RenderSPU( vout_buffer_t *p_buffer, subpicture_t *p_spu,
* i_bytes_per_line; * i_bytes_per_line;
/* Draw until we reach the bottom of the subtitle */ /* Draw until we reach the bottom of the subtitle */
while( i_y < i_height ) for( i_y = 0 ; i_y < i_height ; /* i_y incremented below */ )
{
i_ytmp = i_y >> 6;
i_y += i_yscale;
/* Check whether we need to draw one line or more than one */
if( i_ytmp + 1 >= ( i_y >> 6 ) )
{
/* Just one line : we precalculate i_y >> 6 */
i_yreal = i_bytes_per_line * i_ytmp;
/* Draw until we reach the end of the line */
for( i_x = 0 ; i_x < i_width ; i_x += i_len )
{ {
/* Get RLE information */ /* Get RLE information */
i_len = i_xscale * ( *p_source >> 2 ); i_len = i_xscale * ( *p_source >> 2 );
...@@ -81,26 +92,38 @@ void vout_RenderSPU( vout_buffer_t *p_buffer, subpicture_t *p_spu, ...@@ -81,26 +92,38 @@ void vout_RenderSPU( vout_buffer_t *p_buffer, subpicture_t *p_spu,
if( i_color ) if( i_color )
{ {
memset( p_dest + i_bytes_per_pixel * ( i_x >> 6 ) memset( p_dest + i_bytes_per_pixel * ( i_x >> 6 )
+ i_bytes_per_line * ( i_y >> 6 ), + i_yreal,
p_palette[ i_color ], p_palette[ i_color ],
i_bytes_per_pixel * ( ( i_len >> 6 ) + 1 ) ); i_bytes_per_pixel * ( ( i_len >> 6 ) + 1 ) );
}
}
}
else
{
i_yreal = i_bytes_per_line * i_ytmp;
i_ynext = i_bytes_per_line * i_y >> 6;
/* Draw until we reach the end of the line */
for( i_x = 0 ; i_x < i_width ; i_x += i_len )
{
/* Get RLE information */
i_len = i_xscale * ( *p_source >> 2 );
i_color = *p_source++ & 0x3;
/* Duplicate line if needed */ /* Draw as many lines as needed */
if( i_yscale > 1 << 6 ) if( i_color )
{
for( i_ytmp = i_yreal ;
i_ytmp < i_ynext ;
i_ytmp += i_bytes_per_line )
{ {
memset( p_dest + i_bytes_per_pixel * ( i_x >> 6 ) memset( p_dest + i_bytes_per_pixel * ( i_x >> 6 )
+ i_bytes_per_line * ( ( i_y >> 6 ) + 1 ), + i_ytmp,
p_palette[ i_color ], p_palette[ i_color ],
i_bytes_per_pixel * ( ( i_len >> 6 ) + 1 ) ); i_bytes_per_pixel * ( ( i_len >> 6 ) + 1 ) );
} }
} }
}
/* Check for end of line */
i_x += i_len;
if( i_x >= i_width )
{
i_y += i_yscale;
i_x = 0;
} }
} }
} }
......
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