free( p_vout->p_sys );
return( 1 );
}
+
return( 0 );
}
*****************************************************************************/
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
}
/*****************************************************************************
*****************************************************************************/
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
}
/*****************************************************************************
*****************************************************************************/
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;
- /* For all events in queue */
- while( ggiKbhit( p_vout->p_sys->p_display ) )
+ ggiEventPoll( p_vout->p_sys->p_display, mask, &tv );
+
+ while( ggiEventsQueued( p_vout->p_sys->p_display, mask) )
{
- i_key = ggiGetc( p_vout->p_sys->p_display );
- switch( i_key )
- {
- case 'q':
- /* FIXME pass message ! */
- p_main->p_intf->b_die = 1;
- break;
+ ggiEventRead( p_vout->p_sys->p_display, &event, mask);
- default:
- break;
+ 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;
+
+ 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:
}
}
*****************************************************************************/
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 */
*****************************************************************************/
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 */
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 ) )
{
/* 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 );
}
/* 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 );
}
/* 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;
/* 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
}
/*****************************************************************************
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 )
return( 1 );
}
+ RemoveBits( &p_spudec->bit_stream, 16 );
+
return( 0 );
}
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 )
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 )
{
= 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 */
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 );
}
/*****************************************************************************
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;
* 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_code < 0x040 )
+ {
+ i_code = AddNibble( i_code, p_src, pi_offset );
+
+ if( i_code < 0x0100 )
+ {
+ /* If the 14 first bits are set to 0, then it's a
+ * new line. We emulate it. */
+ if( i_code < 0x0004 )
+ {
+ i_code |= ( i_width - i_x ) << 2;
+ }
+ else
+ {
+ /* We have a boo boo ! */
+ intf_ErrMsg( "spudec error: unknown code %.4x",
+ i_code );
+ return( 1 );
+ }
+ }
+ }
+ }
}
- if( i_x > i_width )
+ if( ( (i_code >> 2) + i_x + i_y * i_width ) > i_height * i_width )
{
- intf_ErrMsg( "spudec error: i_x overflowed, %i > %i",
- i_x, i_width );
+ 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 );
}
- if( i_x == i_width )
- {
- /* byte-align the stream */
- if( pi_index[i_id] & 0x1 )
- {
- pi_index[i_id]++;
- }
-
- i_id = ~i_id & 0x1;
-
- i_y++;
- i_x = 0;
-
- if( i_y > i_height )
- {
- intf_ErrMsg( "spudec error: i_y overflowed at EOL, "
- "%i > %i", i_y, i_height );
- return( 1 );
- }
- }
-
- continue;
+ /* We got a valid code, store it */
+ *p_dest++ = i_code;
}
- i_code = ( i_code << 4 ) + GetNibble( p_source, pi_index + i_id );
-
- /* 00 11 xx cc */
- if( i_code >= 0x10 )
+ /* Check that we didn't go too far */
+ if( i_x > i_width )
{
- /* 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 )
- {
- goto found_code; /* 00 00 01 xx xx cc */
+ intf_ErrMsg( "spudec error: i_x overflowed, %i > %i",
+ i_x, i_width );
+ 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 */
+ /* Byte-align the stream */
+ if( *pi_offset & 0x1 )
{
- goto found_code; /* 00 00 00 01 xx xx xx cc */
+ (*pi_offset)++;
}
- if( i_code & ~0x0003 )
- {
- /* We have a boo boo ! */
- intf_ErrMsg( "spudec error: unknown code 0x%.4x", i_code );
- return( 1 );
- }
- else
- {
- /* If the 14 first bits are 0, then it's a new line */
- 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 */
#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 );
}
}
* 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
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 */
* 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 */ )
{
- /* Get RLE information */
- i_len = i_xscale * ( *p_source >> 2 );
- i_color = *p_source++ & 0x3;
+ i_ytmp = i_y >> 6;
+ i_y += i_yscale;
- /* Draw the line */
- if( i_color )
+ /* Check whether we need to draw one line or more than one */
+ if( i_ytmp + 1 >= ( i_y >> 6 ) )
{
- memset( p_dest + i_bytes_per_pixel * ( i_x >> 6 )
- + i_bytes_per_line * ( i_y >> 6 ),
- p_palette[ i_color ],
- i_bytes_per_pixel * ( ( i_len >> 6 ) + 1 ) );
+ /* Just one line : we precalculate i_y >> 6 */
+ i_yreal = i_bytes_per_line * i_ytmp;
- /* Duplicate line if needed */
- if( i_yscale > 1 << 6 )
+ /* Draw until we reach the end of the line */
+ for( i_x = 0 ; i_x < i_width ; i_x += i_len )
{
- memset( p_dest + i_bytes_per_pixel * ( i_x >> 6 )
- + i_bytes_per_line * ( ( i_y >> 6 ) + 1 ),
- p_palette[ i_color ],
- i_bytes_per_pixel * ( ( i_len >> 6 ) + 1 ) );
+ /* Get RLE information */
+ i_len = i_xscale * ( *p_source >> 2 );
+ i_color = *p_source++ & 0x3;
+
+ /* Draw the line */
+ if( i_color )
+ {
+ memset( p_dest + i_bytes_per_pixel * ( i_x >> 6 )
+ + i_yreal,
+ 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 )
+ else
{
- i_y += i_yscale;
- i_x = 0;
+ 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;
+
+ /* 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_ytmp,
+ p_palette[ i_color ],
+ i_bytes_per_pixel * ( ( i_len >> 6 ) + 1 ) );
+ }
+ }
+ }
}
}
}