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 )
free( p_vout->p_sys );
return( 1 );
}
return( 0 );
}
......@@ -146,13 +147,23 @@ int vout_Create( 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 */
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 );
#undef p_b
}
/*****************************************************************************
......@@ -162,11 +173,13 @@ int vout_Init( vout_thread_t *p_vout )
*****************************************************************************/
void vout_End( vout_thread_t *p_vout )
{
#define p_b p_vout->p_sys->p_buffer
/* Release buffer */
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 )
*****************************************************************************/
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( ggiKbhit( p_vout->p_sys->p_display ) )
while( ggiEventsQueued( p_vout->p_sys->p_display, mask) )
{
i_key = ggiGetc( p_vout->p_sys->p_display );
switch( i_key )
ggiEventRead( p_vout->p_sys->p_display, &event, mask);
switch( event.any.type )
{
case evKeyRelease:
switch( event.key.sym )
{
case 'q':
case 'Q':
case GIIUC_Escape:
/* FIXME pass message ! */
p_main->p_intf->b_die = 1;
break;
......@@ -205,6 +230,21 @@ int vout_Manage( vout_thread_t *p_vout )
default:
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 );
......@@ -218,23 +258,27 @@ int vout_Manage( 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 */
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,
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 */
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 );
}
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 */
......@@ -247,6 +291,7 @@ void vout_Display( 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_color col_fg; /* foreground color */
ggi_color col_bg; /* background color */
......@@ -287,8 +332,7 @@ static int GGIOpenDisplay( vout_thread_t *p_vout )
mode.dpp.y = GGI_AUTO;
ggiCheckMode( p_vout->p_sys->p_display, &mode );
/* Check that returned mode has some minimum properties */
/* XXX?? */
/* FIXME: Check that returned mode has some minimum properties */
/* Set mode */
if( ggiSetMode( p_vout->p_sys->p_display, &mode ) )
......@@ -305,8 +349,9 @@ static int GGIOpenDisplay( vout_thread_t *p_vout )
{
/* Get buffer address */
p_vout->p_sys->p_buffer[ i_index ] =
(ggi_directbuffer *)ggiDBGetBuffer( p_vout->p_sys->p_display, i_index );
if( p_vout->p_sys->p_buffer[ i_index ] == NULL )
(ggi_directbuffer *)ggiDBGetBuffer( p_vout->p_sys->p_display,
i_index );
if( p_b[ i_index ] == NULL )
{
intf_ErrMsg( "vout error: double buffering is not possible" );
ggiClose( p_vout->p_sys->p_display );
......@@ -315,11 +360,11 @@ static int GGIOpenDisplay( vout_thread_t *p_vout )
}
/* Check buffer properties */
if( ! (p_vout->p_sys->p_buffer[ i_index ]->type & GGI_DB_SIMPLE_PLB) ||
(p_vout->p_sys->p_buffer[ i_index ]->page_size != 0) ||
(p_vout->p_sys->p_buffer[ i_index ]->write == NULL ) ||
(p_vout->p_sys->p_buffer[ i_index ]->noaccess != 0) ||
(p_vout->p_sys->p_buffer[ i_index ]->align != 0) )
if( ! ( p_b[ i_index ]->type & GGI_DB_SIMPLE_PLB )
|| ( p_b[ i_index ]->page_size != 0 )
|| ( p_b[ i_index ]->write == NULL )
|| ( p_b[ i_index ]->noaccess != 0 )
|| ( p_b[ i_index ]->align != 0 ) )
{
intf_ErrMsg( "vout error: incorrect video memory type" );
ggiClose( p_vout->p_sys->p_display );
......@@ -328,17 +373,16 @@ static int GGIOpenDisplay( vout_thread_t *p_vout )
}
/* 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;
}
}
#ifdef DEBUG
if( p_vout->p_sys->b_must_acquire )
{
intf_DbgMsg("buffers must be acquired");
}
#endif
/* Set graphic context colors */
col_fg.r = col_fg.g = col_fg.b = -1;
......@@ -367,18 +411,20 @@ static int GGIOpenDisplay( vout_thread_t *p_vout )
/* Set thread information */
p_vout->i_width = mode.visible.x;
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_screen_depth = p_vout->p_sys->p_buffer[ 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_red_mask = p_vout->p_sys->p_buffer[ 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_blue_mask = p_vout->p_sys->p_buffer[ 0 ]->buffer.plb.pixelformat->blue_mask;
/* FIXME: palette in 8bpp ?? */
p_vout->i_bytes_per_line = p_b[ 0 ]->buffer.plb.stride;
p_vout->i_screen_depth = p_b[ 0 ]->buffer.plb.pixelformat->depth;
p_vout->i_bytes_per_pixel = p_b[ 0 ]->buffer.plb.pixelformat->size / 8;
p_vout->i_red_mask = p_b[ 0 ]->buffer.plb.pixelformat->red_mask;
p_vout->i_green_mask = p_b[ 0 ]->buffer.plb.pixelformat->green_mask;
p_vout->i_blue_mask = p_b[ 0 ]->buffer.plb.pixelformat->blue_mask;
/* FIXME: set palette in 8bpp */
/* 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 );
#undef p_b
}
/*****************************************************************************
......
......@@ -213,7 +213,7 @@ static int SyncPacket( spudec_thread_t *p_spudec )
p_spudec->i_spu_size = GetBits( &p_spudec->bit_stream, 16 );
/* 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( p_spudec->i_rle_size >= p_spudec->i_spu_size )
......@@ -221,6 +221,8 @@ static int SyncPacket( spudec_thread_t *p_spudec )
return( 1 );
}
RemoveBits( &p_spudec->bit_stream, 16 );
return( 0 );
}
......@@ -233,7 +235,7 @@ static int SyncPacket( spudec_thread_t *p_spudec )
static void ParsePacket( spudec_thread_t *p_spudec )
{
subpicture_t * p_spu;
u8 * p_source;
u8 * p_src;
/* We cannot display a subpicture with no date */
if( DECODER_FIFO_START(*p_spudec->p_fifo)->i_pts == 0 )
......@@ -246,8 +248,8 @@ static void ParsePacket( spudec_thread_t *p_spudec )
p_spudec->i_rle_size * 4 );
/* 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
* on. This will speed things up a lot. Plus, we won't need to do
* this stupid interlacing stuff. */
* on. This will speed things up a lot. Plus, we'll only need to do
* this stupid interlacing stuff once. */
if( p_spu == NULL )
{
......@@ -259,17 +261,17 @@ static void ParsePacket( spudec_thread_t *p_spudec )
= DECODER_FIFO_START(*p_spudec->p_fifo)->i_pts;
/* 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 );
return;
}
/* 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
/* Dump the subtitle info */
......@@ -280,29 +282,29 @@ static void ParsePacket( spudec_thread_t *p_spudec )
if( ParseControlSequences( p_spudec, p_spu ) )
{
/* There was a parse error, delete the subpicture */
free( p_source );
free( p_src );
vout_DestroySubPicture( p_spudec->p_vout, p_spu );
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] );
if( ParseRLE( p_source, p_spu ) )
if( ParseRLE( p_src, p_spu ) )
{
/* There was a parse error, delete the subpicture */
free( p_source );
free( p_src );
vout_DestroySubPicture( p_spudec->p_vout, p_spu );
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 */
vout_DisplaySubPicture( p_spudec->p_vout, p_spu );
/* Clean up */
free( p_source );
free( p_src );
}
/*****************************************************************************
......@@ -355,14 +357,14 @@ static int ParseControlSequences( spudec_thread_t *p_spudec,
case SPU_CMD_START_DISPLAY:
/* 01 (start displaying) */
p_spu->begin_date += ( i_date * 12000 );
p_spu->begin_date += ( i_date * 11000 );
break;
case SPU_CMD_STOP_DISPLAY:
/* 02 (stop displaying) */
p_spu->end_date += ( i_date * 12000 );
p_spu->end_date += ( i_date * 11000 );
break;
......@@ -484,111 +486,91 @@ static int ParseControlSequences( spudec_thread_t *p_spudec,
* convenient structure for later decoding. For more information on the
* 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;
int i_id = 0;
unsigned int i_code;
unsigned int i_id = 0;
int i_width = p_spu->i_width;
int i_height = p_spu->i_height;
int i_x = 0, i_y = 0;
unsigned int i_width = p_spu->i_width;
unsigned int i_height = p_spu->i_height;
unsigned int i_x, i_y;
u16 *p_dest = (u16 *)p_spu->p_data;
int pi_index[2];
pi_index[0] = p_spu->type.spu.i_offset[0] << 1;
pi_index[1] = p_spu->type.spu.i_offset[1] << 1;
/* The subtitles are interlaced, we need two offsets */
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 "
"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_code = AddNibble( i_code, p_src, pi_offset );
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_x, i_width );
return( 1 );
}
i_code = AddNibble( i_code, p_src, pi_offset );
if( i_x == i_width )
if( i_code < 0x0100 )
{
/* byte-align the stream */
if( pi_index[i_id] & 0x1 )
/* If the 14 first bits are set to 0, then it's a
* new line. We emulate it. */
if( i_code < 0x0004 )
{
pi_index[i_id]++;
i_code |= ( i_width - i_x ) << 2;
}
i_id = ~i_id & 0x1;
i_y++;
i_x = 0;
if( i_y > i_height )
else
{
intf_ErrMsg( "spudec error: i_y overflowed at EOL, "
"%i > %i", i_y, i_height );
/* We have a boo boo ! */
intf_ErrMsg( "spudec error: unknown code %.4x",
i_code );
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 );
/* 00 00 11 xx xx cc */
if( i_code >= 0x040 )
if( ( (i_code >> 2) + i_x + i_y * i_width ) > i_height * i_width )
{
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 );
if( i_code >= 0x0100 ) /* 00 00 00 11 xx xx xx cc */
{
goto found_code; /* 00 00 00 01 xx xx xx cc */
/* We got a valid code, store it */
*p_dest++ = i_code;
}
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: unknown code 0x%.4x", i_code );
intf_ErrMsg( "spudec error: i_x overflowed, %i > %i",
i_x, i_width );
return( 1 );
}
else
/* Byte-align the stream */
if( *pi_offset & 0x1 )
{
/* If the 14 first bits are 0, then it's a new line */
i_code |= ( i_width - i_x ) << 2;
goto found_code;
(*pi_offset)++;
}
/* Swap fields */
i_id = ~i_id & 0x1;
}
/* FIXME: we shouldn't need these padding bytes */
......
......@@ -65,17 +65,18 @@ typedef struct spudec_thread_s
#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 )
{
return( p_source[(*pi_index)++ >> 1] & 0xf );
return( i_code << 4 | ( p_src[(*pi_index)++ >> 1] & 0xf ) );
}
else
{
return( p_source[(*pi_index)++ >> 1] >> 4 );
return( i_code << 4 | p_src[(*pi_index)++ >> 1] >> 4 );
}
}
......
......@@ -4,7 +4,6 @@
* Copyright (C) 1999, 2000 VideoLAN
*
* Authors: Samuel Hocevar <sam@zoy.org>
* Henri Fallon <henri@via.ecp.fr>
*
* 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
......@@ -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_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
/* Add the picture coordinates and the SPU coordinates */
......@@ -71,7 +70,19 @@ void vout_RenderSPU( vout_buffer_t *p_buffer, subpicture_t *p_spu,
* i_bytes_per_line;
/* 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 */
i_len = i_xscale * ( *p_source >> 2 );
......@@ -81,26 +92,38 @@ void vout_RenderSPU( vout_buffer_t *p_buffer, subpicture_t *p_spu,
if( i_color )
{
memset( p_dest + i_bytes_per_pixel * ( i_x >> 6 )
+ i_bytes_per_line * ( i_y >> 6 ),
+ i_yreal,
p_palette[ i_color ],
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 */
if( i_yscale > 1 << 6 )
/* Draw as many lines as needed */
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 )
+ i_bytes_per_line * ( ( i_y >> 6 ) + 1 ),
+ i_ytmp,
p_palette[ i_color ],
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