Commit 8b09b55d authored by Sam Hocevar's avatar Sam Hocevar

* ./modules/access/dvdplay/access.c: activated button highlighting.

  * ./modules/codec/spudec/parse.c: implemented subtitle cropping and
    temporarily disabled subtitle cropping.
  * ./modules/codec/spudec/render.c: split RenderSPU into chroma-specific
    functions.
parent 2401b662
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
* includes all common video types and constants. * includes all common video types and constants.
***************************************************************************** *****************************************************************************
* Copyright (C) 1999, 2000 VideoLAN * Copyright (C) 1999, 2000 VideoLAN
* $Id: video.h,v 1.56 2002/07/23 00:39:16 sam Exp $ * $Id: video.h,v 1.57 2002/11/06 18:07:57 sam Exp $
* *
* Authors: Vincent Seguin <seguin@via.ecp.fr> * Authors: Vincent Seguin <seguin@via.ecp.fr>
* *
...@@ -166,7 +166,6 @@ struct subpicture_t ...@@ -166,7 +166,6 @@ struct subpicture_t
/* Type and flags - should NOT be modified except by the vout thread */ /* Type and flags - should NOT be modified except by the vout thread */
int i_type; /* type */ int i_type; /* type */
int i_status; /* flags */ int i_status; /* flags */
int i_size; /* data size */
subpicture_t * p_next; /* next subtitle to be displayed */ subpicture_t * p_next; /* next subtitle to be displayed */
/* Date properties */ /* Date properties */
...@@ -199,13 +198,13 @@ struct subpicture_t ...@@ -199,13 +198,13 @@ struct subpicture_t
} type; } type;
#endif #endif
/* The subpicture rendering routine */ /* The subpicture rendering and destruction routines */
void ( *pf_render ) ( vout_thread_t *, picture_t *, const subpicture_t * ); void ( *pf_render ) ( vout_thread_t *, picture_t *, const subpicture_t * );
void ( *pf_destroy ) ( subpicture_t * );
/* Private data - the subtitle plugin might want to put stuff here to /* Private data - the subtitle plugin might want to put stuff here to
* keep track of the subpicture */ * keep track of the subpicture */
subpicture_sys_t *p_sys; /* subpicture data */ subpicture_sys_t *p_sys; /* subpicture data */
void *p_sys_orig; /* pointer before memalign */
}; };
/* Subpicture type */ /* Subpicture type */
...@@ -216,5 +215,4 @@ struct subpicture_t ...@@ -216,5 +215,4 @@ struct subpicture_t
#define FREE_SUBPICTURE 0 /* free and not allocated */ #define FREE_SUBPICTURE 0 /* free and not allocated */
#define RESERVED_SUBPICTURE 1 /* allocated and reserved */ #define RESERVED_SUBPICTURE 1 /* allocated and reserved */
#define READY_SUBPICTURE 2 /* ready for display */ #define READY_SUBPICTURE 2 /* ready for display */
#define DESTROYED_SUBPICTURE 3 /* allocated but not used anymore */
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
* thread, and destroy a previously opened video output thread. * thread, and destroy a previously opened video output thread.
***************************************************************************** *****************************************************************************
* Copyright (C) 1999, 2000 VideoLAN * Copyright (C) 1999, 2000 VideoLAN
* $Id: video_output.h,v 1.84 2002/10/17 16:03:18 sam Exp $ * $Id: video_output.h,v 1.85 2002/11/06 18:07:57 sam Exp $
* *
* Authors: Vincent Seguin <seguin@via.ecp.fr> * Authors: Vincent Seguin <seguin@via.ecp.fr>
* Samuel Hocevar <sam@via.ecp.fr> * Samuel Hocevar <sam@via.ecp.fr>
...@@ -158,7 +158,7 @@ VLC_EXPORT( void, vout_PlacePicture, ( vout_thread_t *, int, int, i ...@@ -158,7 +158,7 @@ VLC_EXPORT( void, vout_PlacePicture, ( vout_thread_t *, int, int, i
picture_t * vout_RenderPicture ( vout_thread_t *, picture_t *, picture_t * vout_RenderPicture ( vout_thread_t *, picture_t *,
subpicture_t * ); subpicture_t * );
VLC_EXPORT( subpicture_t *, vout_CreateSubPicture, ( vout_thread_t *, int, int ) ); VLC_EXPORT( subpicture_t *, vout_CreateSubPicture, ( vout_thread_t *, int ) );
VLC_EXPORT( void, vout_DestroySubPicture, ( vout_thread_t *, subpicture_t * ) ); VLC_EXPORT( void, vout_DestroySubPicture, ( vout_thread_t *, subpicture_t * ) );
VLC_EXPORT( void, vout_DisplaySubPicture, ( vout_thread_t *, subpicture_t * ) ); VLC_EXPORT( void, vout_DisplaySubPicture, ( vout_thread_t *, subpicture_t * ) );
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* access.c: access capabilities for dvdplay plugin. * access.c: access capabilities for dvdplay plugin.
***************************************************************************** *****************************************************************************
* Copyright (C) 2001 VideoLAN * Copyright (C) 2001 VideoLAN
* $Id: access.c,v 1.4 2002/10/26 15:24:19 gbazin Exp $ * $Id: access.c,v 1.5 2002/11/06 18:07:57 sam Exp $
* *
* Author: Stphane Borel <stef@via.ecp.fr> * Author: Stphane Borel <stef@via.ecp.fr>
* *
...@@ -87,7 +87,7 @@ int E_(OpenDVD) ( vlc_object_t *p_this ) ...@@ -87,7 +87,7 @@ int E_(OpenDVD) ( vlc_object_t *p_this )
p_dvd = malloc( sizeof(dvd_data_t) ); p_dvd = malloc( sizeof(dvd_data_t) );
if( p_dvd == NULL ) if( p_dvd == NULL )
{ {
msg_Err( p_input, "dvdplay error: out of memory" ); msg_Err( p_input, "out of memory" );
return -1; return -1;
} }
...@@ -114,7 +114,7 @@ int E_(OpenDVD) ( vlc_object_t *p_this ) ...@@ -114,7 +114,7 @@ int E_(OpenDVD) ( vlc_object_t *p_this )
if( p_dvd->vmg == NULL ) if( p_dvd->vmg == NULL )
{ {
msg_Err( p_input, "dvdplay error: can't open source" ); msg_Err( p_input, "cannot open %s", psz_source );
free( p_dvd ); free( p_dvd );
return -1; return -1;
} }
...@@ -184,6 +184,18 @@ int E_(OpenDVD) ( vlc_object_t *p_this ) ...@@ -184,6 +184,18 @@ int E_(OpenDVD) ( vlc_object_t *p_this )
p_input->psz_demux = "dvdplay"; p_input->psz_demux = "dvdplay";
/* FIXME: we might lose variables here */
var_Create( p_input, "x-start", VLC_VAR_INTEGER );
var_Create( p_input, "y-start", VLC_VAR_INTEGER );
var_Create( p_input, "x-end", VLC_VAR_INTEGER );
var_Create( p_input, "y-end", VLC_VAR_INTEGER );
var_Create( p_input, "color", VLC_VAR_ADDRESS );
var_Create( p_input, "contrast", VLC_VAR_ADDRESS );
var_Create( p_input, "highlight", VLC_VAR_BOOL );
var_Create( p_input, "highlight-mutex", VLC_VAR_MUTEX );
return 0; return 0;
} }
...@@ -195,6 +207,17 @@ void E_(CloseDVD) ( vlc_object_t *p_this ) ...@@ -195,6 +207,17 @@ void E_(CloseDVD) ( vlc_object_t *p_this )
input_thread_t * p_input = (input_thread_t *)p_this; input_thread_t * p_input = (input_thread_t *)p_this;
dvd_data_t * p_dvd = (dvd_data_t *)p_input->p_access_data; dvd_data_t * p_dvd = (dvd_data_t *)p_input->p_access_data;
var_Destroy( p_input, "highlight-mutex" );
var_Destroy( p_input, "highlight" );
var_Destroy( p_input, "x-start" );
var_Destroy( p_input, "x-end" );
var_Destroy( p_input, "y-start" );
var_Destroy( p_input, "y-end" );
var_Destroy( p_input, "color" );
var_Destroy( p_input, "contrast" );
/* close libdvdplay */ /* close libdvdplay */
dvdplay_close( p_dvd->vmg ); dvdplay_close( p_dvd->vmg );
...@@ -350,6 +373,7 @@ static void pf_vmg_callback( void* p_args, dvdplay_event_t event ) ...@@ -350,6 +373,7 @@ static void pf_vmg_callback( void* p_args, dvdplay_event_t event )
{ {
input_thread_t * p_input; input_thread_t * p_input;
dvd_data_t * p_dvd; dvd_data_t * p_dvd;
vlc_value_t val;
int i; int i;
p_input = (input_thread_t*)p_args; p_input = (input_thread_t*)p_args;
...@@ -407,11 +431,38 @@ static void pf_vmg_callback( void* p_args, dvdplay_event_t event ) ...@@ -407,11 +431,38 @@ static void pf_vmg_callback( void* p_args, dvdplay_event_t event )
case COMPLETE_VIDEO: case COMPLETE_VIDEO:
break; break;
case NEW_HIGHLIGHT: case NEW_HIGHLIGHT:
if( var_Get( p_input, "highlight-mutex", &val ) == VLC_SUCCESS )
{
vlc_mutex_t *p_mutex = val.p_address;
vlc_mutex_lock( p_mutex );
/* Retrieve the highlight from dvdplay */
dvdplay_highlight( p_dvd->vmg, &p_dvd->hli );
/* Fill our internal variables with this data */
val.i_int = p_dvd->hli.i_x_start;
var_Set( p_input, "x-start", val );
val.i_int = p_dvd->hli.i_y_start;
var_Set( p_input, "y-start", val );
val.i_int = p_dvd->hli.i_x_end;
var_Set( p_input, "x-end", val );
val.i_int = p_dvd->hli.i_y_end;
var_Set( p_input, "y-end", val );
val.p_address = (void *)p_dvd->hli.pi_color;
var_Set( p_input, "color", val );
val.p_address = (void *)p_dvd->hli.pi_contrast;
var_Set( p_input, "contrast", val );
/* Tell the SPU decoder that there's a new highlight */
val.b_bool = VLC_TRUE;
var_Set( p_input, "highlight", val );
vlc_mutex_unlock( p_mutex );
}
break; break;
default: default:
msg_Err( p_input, "unknown event from libdvdplay (%d)", msg_Err( p_input, "unknown event from libdvdplay (%d)", event );
event );
} }
return; return;
...@@ -494,3 +545,4 @@ static int dvdNewPGC( input_thread_t * p_input ) ...@@ -494,3 +545,4 @@ static int dvdNewPGC( input_thread_t * p_input )
return 0; return 0;
} }
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* dvd.h: structure of the dvdplay plugin * dvd.h: structure of the dvdplay plugin
***************************************************************************** *****************************************************************************
* Copyright (C) 1999-2001 VideoLAN * Copyright (C) 1999-2001 VideoLAN
* $Id: dvd.h,v 1.1 2002/08/04 17:23:42 sam Exp $ * $Id: dvd.h,v 1.2 2002/11/06 18:07:57 sam Exp $
* *
* Author: Stphane Borel <stef@via.ecp.fr> * Author: Stphane Borel <stef@via.ecp.fr>
* *
...@@ -56,6 +56,7 @@ typedef struct ...@@ -56,6 +56,7 @@ typedef struct
dvdplay_event_t event; dvdplay_event_t event;
dvdplay_ctrl_t control; dvdplay_ctrl_t control;
dvdplay_highlight_t hli;
} dvd_data_t; } dvd_data_t;
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* intf.c: interface for DVD video manager * intf.c: interface for DVD video manager
***************************************************************************** *****************************************************************************
* Copyright (C) 2002 VideoLAN * Copyright (C) 2002 VideoLAN
* $Id: intf.c,v 1.2 2002/10/17 16:03:18 sam Exp $ * $Id: intf.c,v 1.3 2002/11/06 18:07:57 sam Exp $
* *
* Authors: Stphane Borel <stef@via.ecp.fr> * Authors: Stphane Borel <stef@via.ecp.fr>
* *
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
#include "stream_control.h" #include "stream_control.h"
#include "input_ext-intf.h" #include "input_ext-intf.h"
#include "input_ext-dec.h"
#include "dvd.h" #include "dvd.h"
...@@ -190,10 +191,6 @@ static void RunIntf( intf_thread_t *p_intf ) ...@@ -190,10 +191,6 @@ static void RunIntf( intf_thread_t *p_intf )
p_intf->p_sys->b_move = VLC_FALSE; p_intf->p_sys->b_move = VLC_FALSE;
} }
msg_Dbg( p_intf, "send button coordinates: %dx%d",
p_intf->p_sys->control.mouse.i_x,
p_intf->p_sys->control.mouse.i_y );
/* we can safely interact with libdvdplay /* we can safely interact with libdvdplay
* with the stream lock */ * with the stream lock */
vlc_mutex_lock( &p_intf->p_sys->p_input->stream.stream_lock ); vlc_mutex_lock( &p_intf->p_sys->p_input->stream.stream_lock );
...@@ -343,7 +340,6 @@ int dvdIntfStillTime( intf_thread_t *p_intf, int i_sec ) ...@@ -343,7 +340,6 @@ int dvdIntfStillTime( intf_thread_t *p_intf, int i_sec )
#endif #endif
vlc_mutex_unlock( &p_intf->change_lock ); vlc_mutex_unlock( &p_intf->change_lock );
return 0; return VLC_SUCCESS;
} }
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* parse.c: SPU parser * parse.c: SPU parser
***************************************************************************** *****************************************************************************
* Copyright (C) 2000-2001 VideoLAN * Copyright (C) 2000-2001 VideoLAN
* $Id: parse.c,v 1.3 2002/10/31 09:40:26 gbazin Exp $ * $Id: parse.c,v 1.4 2002/11/06 18:07:57 sam Exp $
* *
* Authors: Samuel Hocevar <sam@zoy.org> * Authors: Samuel Hocevar <sam@zoy.org>
* *
...@@ -44,14 +44,20 @@ ...@@ -44,14 +44,20 @@
/***************************************************************************** /*****************************************************************************
* Local prototypes. * Local prototypes.
*****************************************************************************/ *****************************************************************************/
static int ParseControlSequences( spudec_thread_t *, subpicture_t * ); static int ParseControlSeq ( spudec_thread_t *, subpicture_t * );
static int ParseRLE ( spudec_thread_t *, subpicture_t *, u8 * ); static int ParseRLE ( spudec_thread_t *, subpicture_t *, uint8_t * );
static void DestroySPU ( subpicture_t * );
static void UpdateSPU ( subpicture_t *, vlc_object_t * );
static int CropCallback ( vlc_object_t *, char const *,
vlc_value_t, vlc_value_t, void * );
/***************************************************************************** /*****************************************************************************
* AddNibble: read a nibble from a source packet and add it to our integer. * AddNibble: read a nibble from a source packet and add it to our integer.
*****************************************************************************/ *****************************************************************************/
static inline unsigned int AddNibble( unsigned int i_code, static inline unsigned int AddNibble( unsigned int i_code,
u8 *p_src, int *pi_index ) uint8_t *p_src, int *pi_index )
{ {
if( *pi_index & 0x1 ) if( *pi_index & 0x1 )
{ {
...@@ -101,7 +107,7 @@ int E_(SyncPacket)( spudec_thread_t *p_spudec ) ...@@ -101,7 +107,7 @@ int E_(SyncPacket)( spudec_thread_t *p_spudec )
void E_(ParsePacket)( spudec_thread_t *p_spudec ) void E_(ParsePacket)( spudec_thread_t *p_spudec )
{ {
subpicture_t * p_spu; subpicture_t * p_spu;
u8 * p_src; uint8_t * p_src;
unsigned int i_offset; unsigned int i_offset;
mtime_t i_pts; mtime_t i_pts;
...@@ -117,22 +123,32 @@ void E_(ParsePacket)( spudec_thread_t *p_spudec ) ...@@ -117,22 +123,32 @@ void E_(ParsePacket)( spudec_thread_t *p_spudec )
} }
/* Allocate the subpicture internal data. */ /* Allocate the subpicture internal data. */
p_spu = vout_CreateSubPicture( p_spudec->p_vout, MEMORY_SUBPICTURE, p_spu = vout_CreateSubPicture( p_spudec->p_vout, MEMORY_SUBPICTURE );
sizeof( subpicture_sys_t )
+ p_spudec->i_rle_size * 4 ); if( p_spu == NULL )
{
return;
}
/* 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'll only need to do * on. This will speed things up a lot. Plus, we'll only need to do
* this stupid interlacing stuff once. */ * this stupid interlacing stuff once. */
p_spu->p_sys = malloc( sizeof( subpicture_sys_t )
+ p_spudec->i_rle_size * 4 );
if( p_spu == NULL ) if( p_spu->p_sys == NULL )
{ {
vout_DestroySubPicture( p_spudec->p_vout, p_spu );
return; return;
} }
/* Fill the p_spu structure */ /* Fill the p_spu structure */
vlc_mutex_init( p_spudec->p_fifo, &p_spu->p_sys->lock );
p_spu->pf_render = E_(RenderSPU); p_spu->pf_render = E_(RenderSPU);
p_spu->p_sys->p_data = (u8*)p_spu->p_sys + sizeof( subpicture_sys_t ); p_spu->pf_destroy = DestroySPU;
p_spu->p_sys->p_data = (uint8_t*)p_spu->p_sys + sizeof( subpicture_sys_t );
p_spu->p_sys->b_palette = VLC_FALSE; p_spu->p_sys->b_palette = VLC_FALSE;
p_spu->p_sys->pi_alpha[0] = 0x00; p_spu->p_sys->pi_alpha[0] = 0x00;
...@@ -140,9 +156,30 @@ void E_(ParsePacket)( spudec_thread_t *p_spudec ) ...@@ -140,9 +156,30 @@ void E_(ParsePacket)( spudec_thread_t *p_spudec )
p_spu->p_sys->pi_alpha[2] = 0x0f; p_spu->p_sys->pi_alpha[2] = 0x0f;
p_spu->p_sys->pi_alpha[3] = 0x0f; p_spu->p_sys->pi_alpha[3] = 0x0f;
p_spu->p_sys->b_crop = VLC_FALSE;
/* Get display time now. If we do it later, we may miss the PTS. */ /* Get display time now. If we do it later, we may miss the PTS. */
p_spu->p_sys->i_pts = i_pts; p_spu->p_sys->i_pts = i_pts;
/* Attach to our input thread */
p_spu->p_sys->p_input = vlc_object_find( p_spudec->p_fifo,
VLC_OBJECT_INPUT, FIND_PARENT );
if( p_spu->p_sys->p_input )
{
vlc_value_t val;
if( !var_Get( p_spu->p_sys->p_input, "highlight-mutex", &val ) )
{
vlc_mutex_t *p_mutex = val.p_address;
vlc_mutex_lock( p_mutex );
UpdateSPU( p_spu, VLC_OBJECT(p_spu->p_sys->p_input) );
var_AddCallback( p_spu->p_sys->p_input,
"highlight", CropCallback, p_spu );
vlc_mutex_unlock( p_mutex );
}
}
/* Allocate the temporary buffer we will parse */ /* Allocate the temporary buffer we will parse */
p_src = malloc( p_spudec->i_rle_size ); p_src = malloc( p_spudec->i_rle_size );
...@@ -176,7 +213,7 @@ void E_(ParsePacket)( spudec_thread_t *p_spudec ) ...@@ -176,7 +213,7 @@ void E_(ParsePacket)( spudec_thread_t *p_spudec )
#endif #endif
/* Getting the control part */ /* Getting the control part */
if( ParseControlSequences( p_spudec, p_spu ) ) if( ParseControlSeq( p_spudec, p_spu ) )
{ {
/* There was a parse error, delete the subpicture */ /* There was a parse error, delete the subpicture */
free( p_src ); free( p_src );
...@@ -203,18 +240,20 @@ void E_(ParsePacket)( spudec_thread_t *p_spudec ) ...@@ -203,18 +240,20 @@ void E_(ParsePacket)( spudec_thread_t *p_spudec )
/* SPU is finished - we can ask the video output to display it */ /* SPU is finished - we can ask the video output to display it */
vout_DisplaySubPicture( p_spudec->p_vout, p_spu ); vout_DisplaySubPicture( p_spudec->p_vout, p_spu );
/* TODO: do stuff! */
/* Clean up */ /* Clean up */
free( p_src ); free( p_src );
} }
/***************************************************************************** /*****************************************************************************
* ParseControlSequences: parse all SPU control sequences * ParseControlSeq: parse all SPU control sequences
***************************************************************************** *****************************************************************************
* This is the most important part in SPU decoding. We get dates, palette * This is the most important part in SPU decoding. We get dates, palette
* information, coordinates, and so on. For more information on the * information, coordinates, and so on. 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 ParseControlSequences( spudec_thread_t *p_spudec, static int ParseControlSeq( spudec_thread_t *p_spudec,
subpicture_t * p_spu ) subpicture_t * p_spu )
{ {
/* Our current index in the SPU packet */ /* Our current index in the SPU packet */
...@@ -224,7 +263,7 @@ static int ParseControlSequences( spudec_thread_t *p_spudec, ...@@ -224,7 +263,7 @@ static int ParseControlSequences( spudec_thread_t *p_spudec,
int i_next_seq = 0, i_cur_seq = 0; int i_next_seq = 0, i_cur_seq = 0;
/* Command and date */ /* Command and date */
u8 i_command = SPU_CMD_END; uint8_t i_command = SPU_CMD_END;
mtime_t date = 0; mtime_t date = 0;
int i, pi_alpha[4]; int i, pi_alpha[4];
...@@ -275,12 +314,12 @@ static int ParseControlSequences( spudec_thread_t *p_spudec, ...@@ -275,12 +314,12 @@ static int ParseControlSequences( spudec_thread_t *p_spudec,
if( p_spudec->p_fifo->p_demux_data if( p_spudec->p_fifo->p_demux_data
&& *(int*)p_spudec->p_fifo->p_demux_data == 0xBeeF ) && *(int*)p_spudec->p_fifo->p_demux_data == 0xBeeF )
{ {
u32 i_color; uint32_t i_color;
p_spu->p_sys->b_palette = VLC_TRUE; p_spu->p_sys->b_palette = VLC_TRUE;
for( i = 0; i < 4 ; i++ ) for( i = 0; i < 4 ; i++ )
{ {
i_color = ((u32*)((char*)p_spudec->p_fifo-> i_color = ((uint32_t*)((char*)p_spudec->p_fifo->
p_demux_data + sizeof(int)))[ p_demux_data + sizeof(int)))[
GetBits(&p_spudec->bit_stream, 4) ]; GetBits(&p_spudec->bit_stream, 4) ];
...@@ -431,7 +470,7 @@ static int ParseControlSequences( spudec_thread_t *p_spudec, ...@@ -431,7 +470,7 @@ static int ParseControlSequences( spudec_thread_t *p_spudec,
* 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( spudec_thread_t *p_spudec, static int ParseRLE( spudec_thread_t *p_spudec,
subpicture_t * p_spu, u8 * p_src ) subpicture_t * p_spu, uint8_t * p_src )
{ {
unsigned int i_code; unsigned int i_code;
...@@ -439,17 +478,19 @@ static int ParseRLE( spudec_thread_t *p_spudec, ...@@ -439,17 +478,19 @@ static int ParseRLE( spudec_thread_t *p_spudec,
unsigned int i_height = p_spu->i_height; unsigned int i_height = p_spu->i_height;
unsigned int i_x, i_y; unsigned int i_x, i_y;
u16 *p_dest = (u16 *)p_spu->p_sys->p_data; uint16_t *p_dest = (uint16_t *)p_spu->p_sys->p_data;
/* The subtitles are interlaced, we need two offsets */ /* The subtitles are interlaced, we need two offsets */
unsigned int i_id = 0; /* Start on the even SPU layer */ unsigned int i_id = 0; /* Start on the even SPU layer */
unsigned int pi_table[ 2 ]; unsigned int pi_table[ 2 ];
unsigned int *pi_offset; unsigned int *pi_offset;
#if 0 /* cropping */
vlc_bool_t b_empty_top = VLC_TRUE, vlc_bool_t b_empty_top = VLC_TRUE,
b_empty_bottom = VLC_FALSE; b_empty_bottom = VLC_FALSE;
unsigned int i_skipped_top = 0, unsigned int i_skipped_top = 0,
i_skipped_bottom = 0; i_skipped_bottom = 0;
#endif
/* Colormap statistics */ /* Colormap statistics */
int i_border = -1; int i_border = -1;
...@@ -513,6 +554,7 @@ static int ParseRLE( spudec_thread_t *p_spudec, ...@@ -513,6 +554,7 @@ static int ParseRLE( spudec_thread_t *p_spudec,
stats[i_border] += i_code >> 2; stats[i_border] += i_code >> 2;
} }
#if 0 /* cropping */
if( (i_code >> 2) == i_width if( (i_code >> 2) == i_width
&& p_spu->p_sys->pi_alpha[ i_code & 0x3 ] == 0x00 ) && p_spu->p_sys->pi_alpha[ i_code & 0x3 ] == 0x00 )
{ {
...@@ -541,6 +583,9 @@ static int ParseRLE( spudec_thread_t *p_spudec, ...@@ -541,6 +583,9 @@ static int ParseRLE( spudec_thread_t *p_spudec,
b_empty_bottom = VLC_FALSE; b_empty_bottom = VLC_FALSE;
i_skipped_bottom = 0; i_skipped_bottom = 0;
} }
#else
*p_dest++ = i_code;
#endif
} }
/* Check that we didn't go too far */ /* Check that we didn't go too far */
...@@ -581,6 +626,7 @@ static int ParseRLE( spudec_thread_t *p_spudec, ...@@ -581,6 +626,7 @@ static int ParseRLE( spudec_thread_t *p_spudec,
msg_Dbg( p_spudec->p_fifo, "valid subtitle, size: %ix%i, position: %i,%i", msg_Dbg( p_spudec->p_fifo, "valid subtitle, size: %ix%i, position: %i,%i",
p_spu->i_width, p_spu->i_height, p_spu->i_x, p_spu->i_y ); p_spu->i_width, p_spu->i_height, p_spu->i_x, p_spu->i_y );
#if 0 /* cropping */
/* Crop if necessary */ /* Crop if necessary */
if( i_skipped_top || i_skipped_bottom ) if( i_skipped_top || i_skipped_bottom )
{ {
...@@ -590,6 +636,7 @@ static int ParseRLE( spudec_thread_t *p_spudec, ...@@ -590,6 +636,7 @@ static int ParseRLE( spudec_thread_t *p_spudec,
msg_Dbg( p_spudec->p_fifo, "cropped to: %ix%i, position: %i,%i", msg_Dbg( p_spudec->p_fifo, "cropped to: %ix%i, position: %i,%i",
p_spu->i_width, p_spu->i_height, p_spu->i_x, p_spu->i_y ); p_spu->i_width, p_spu->i_height, p_spu->i_x, p_spu->i_y );
} }
#endif
/* Handle color if no palette was found */ /* Handle color if no palette was found */
if( !p_spu->p_sys->b_palette ) if( !p_spu->p_sys->b_palette )
...@@ -651,3 +698,82 @@ static int ParseRLE( spudec_thread_t *p_spudec, ...@@ -651,3 +698,82 @@ static int ParseRLE( spudec_thread_t *p_spudec,
return VLC_SUCCESS; return VLC_SUCCESS;
} }
/*****************************************************************************
* DestroySPU: subpicture destructor
*****************************************************************************/
static void DestroySPU( subpicture_t *p_spu )
{
if( p_spu->p_sys->p_input )
{
/* Detach from our input thread */
var_DelCallback( p_spu->p_sys->p_input, "highlight",
CropCallback, p_spu );
vlc_object_release( p_spu->p_sys->p_input );
}
vlc_mutex_destroy( &p_spu->p_sys->lock );
free( p_spu->p_sys );
}
/*****************************************************************************
* UpdateSPU: update subpicture settings
*****************************************************************************
* This function is called from CropCallback and at initialization time, to
* retrieve crop information from the input.
*****************************************************************************/
static void UpdateSPU( subpicture_t *p_spu, vlc_object_t *p_object )
{
vlc_value_t val;
if( var_Get( p_object, "highlight", &val ) )
{
return;
}
p_spu->p_sys->b_crop = val.b_bool;
if( !p_spu->p_sys->b_crop )
{
return;
}
var_Get( p_object, "x-start", &val );
p_spu->p_sys->i_x_start = val.i_int;
var_Get( p_object, "y-start", &val );
p_spu->p_sys->i_y_start = val.i_int;
var_Get( p_object, "x-end", &val );
p_spu->p_sys->i_x_end = val.i_int;
var_Get( p_object, "y-end", &val );
p_spu->p_sys->i_y_end = val.i_int;
#if 0
if( var_Get( p_object, "color", &val ) == VLC_SUCCESS )
{
p_spu->p_sys->pi_color[0] = ((uint8_t *)val.p_address)[0];
p_spu->p_sys->pi_color[1] = ((uint8_t *)val.p_address)[1];
p_spu->p_sys->pi_color[2] = ((uint8_t *)val.p_address)[2];
p_spu->p_sys->pi_color[3] = ((uint8_t *)val.p_address)[3];
}
#endif
if( var_Get( p_object, "contrast", &val ) == VLC_SUCCESS )
{
p_spu->p_sys->pi_alpha[0] = ((uint8_t *)val.p_address)[0];
p_spu->p_sys->pi_alpha[1] = ((uint8_t *)val.p_address)[1];
p_spu->p_sys->pi_alpha[2] = ((uint8_t *)val.p_address)[2];
p_spu->p_sys->pi_alpha[3] = ((uint8_t *)val.p_address)[3];
}
}
/*****************************************************************************
* CropCallback: called when the highlight properties are changed
*****************************************************************************
* This callback is called from the input thread when we need cropping
*****************************************************************************/
static int CropCallback( vlc_object_t *p_object, char const *psz_var,
vlc_value_t oldval, vlc_value_t newval, void *p_data )
{
UpdateSPU( (subpicture_t *)p_data, p_object );
return VLC_SUCCESS;
}
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* render.c : SPU renderer * render.c : SPU renderer
***************************************************************************** *****************************************************************************
* Copyright (C) 2000-2001 VideoLAN * Copyright (C) 2000-2001 VideoLAN
* $Id: render.c,v 1.2 2002/09/30 18:30:26 titer Exp $ * $Id: render.c,v 1.3 2002/11/06 18:07:57 sam Exp $
* *
* Authors: Samuel Hocevar <sam@zoy.org> * Authors: Samuel Hocevar <sam@zoy.org>
* Rudolf Cornelissen <rag.cornelissen@inter.nl.net> * Rudolf Cornelissen <rag.cornelissen@inter.nl.net>
...@@ -43,6 +43,18 @@ ...@@ -43,6 +43,18 @@
#include "spudec.h" #include "spudec.h"
/*****************************************************************************
* Local prototypes
*****************************************************************************/
static void RenderI420( vout_thread_t *, picture_t *, const subpicture_t *,
vlc_bool_t );
static void RenderRV16( vout_thread_t *, picture_t *, const subpicture_t *,
vlc_bool_t );
static void RenderRV32( vout_thread_t *, picture_t *, const subpicture_t *,
vlc_bool_t );
static void RenderYUY2( vout_thread_t *, picture_t *, const subpicture_t *,
vlc_bool_t );
/***************************************************************************** /*****************************************************************************
* RenderSPU: draw an SPU on a picture * RenderSPU: draw an SPU on a picture
***************************************************************************** *****************************************************************************
...@@ -53,10 +65,44 @@ ...@@ -53,10 +65,44 @@
*****************************************************************************/ *****************************************************************************/
void E_(RenderSPU)( vout_thread_t *p_vout, picture_t *p_pic, void E_(RenderSPU)( vout_thread_t *p_vout, picture_t *p_pic,
const subpicture_t *p_spu ) const subpicture_t *p_spu )
{
switch( p_vout->output.i_chroma )
{
/* I420 target, no scaling */
case VLC_FOURCC('I','4','2','0'):
case VLC_FOURCC('I','Y','U','V'):
case VLC_FOURCC('Y','V','1','2'):
RenderI420( p_vout, p_pic, p_spu, p_spu->p_sys->b_crop );
break;
/* RV16 target, scaling */
case VLC_FOURCC('R','V','1','6'):
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'):
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, p_spu->p_sys->b_crop );
break;
default:
msg_Err( p_vout, "unknown chroma, can't render SPU" );
break;
}
}
/* Following functions are local */
static void RenderI420( vout_thread_t *p_vout, picture_t *p_pic,
const subpicture_t *p_spu, vlc_bool_t b_crop )
{ {
/* Common variables */ /* Common variables */
u16 p_clut16[4];
u32 p_clut32[4];
u8 *p_dest; u8 *p_dest;
u8 *p_destptr; u8 *p_destptr;
u16 *p_source = (u16 *)p_spu->p_sys->p_data; u16 *p_source = (u16 *)p_spu->p_sys->p_data;
...@@ -64,33 +110,37 @@ void E_(RenderSPU)( vout_thread_t *p_vout, picture_t *p_pic, ...@@ -64,33 +110,37 @@ void E_(RenderSPU)( vout_thread_t *p_vout, picture_t *p_pic,
int i_x, i_y; int i_x, i_y;
int i_len, i_color; int i_len, i_color;
u16 i_colprecomp, i_destalpha; u16 i_colprecomp, i_destalpha;
u8 i_cnt;
/* RGB-specific */
int i_xscale, i_yscale, i_width, i_height, i_ytmp, i_yreal, i_ynext;
switch( p_vout->output.i_chroma ) /* Crop-specific */
{ int i_x_start, i_y_start, i_x_end, i_y_end;
/* I420 target, no scaling */
case VLC_FOURCC('I','4','2','0'):
case VLC_FOURCC('I','Y','U','V'):
case VLC_FOURCC('Y','V','1','2'):
p_dest = p_pic->Y_PIXELS + p_spu->i_x + p_spu->i_width p_dest = p_pic->Y_PIXELS + p_spu->i_x + p_spu->i_width
+ p_pic->Y_PITCH * ( p_spu->i_y + p_spu->i_height ); + p_pic->Y_PITCH * ( p_spu->i_y + p_spu->i_height );
i_x_start = p_spu->i_width - p_spu->p_sys->i_x_end;
i_y_start = p_pic->Y_PITCH * (p_spu->i_height - p_spu->p_sys->i_y_end );
i_x_end = p_spu->i_width - p_spu->p_sys->i_x_start;
i_y_end = p_pic->Y_PITCH * (p_spu->i_height - p_spu->p_sys->i_y_start );
/* Draw until we reach the bottom of the subtitle */ /* Draw until we reach the bottom of the subtitle */
for( i_y = p_spu->i_height * p_pic->Y_PITCH ; for( i_y = p_spu->i_height * p_pic->Y_PITCH ;
i_y ; i_y ;
i_y -= p_pic->Y_PITCH ) i_y -= p_pic->Y_PITCH )
{ {
/* Draw until we reach the end of the line */ /* Draw until we reach the end of the line */
for( i_x = p_spu->i_width ; i_x ; ) for( i_x = p_spu->i_width ; i_x ; i_x -= i_len )
{ {
/* Get the RLE part, then draw the line */ /* Get the RLE part, then draw the line */
i_color = *p_source & 0x3; i_color = *p_source & 0x3;
i_len = *p_source++ >> 2; i_len = *p_source++ >> 2;
if( b_crop
&& ( i_x < i_x_start || i_x > i_x_end
|| i_y < i_y_start || i_y > i_y_end ) )
{
continue;
}
switch( p_spu->p_sys->pi_alpha[i_color] ) switch( p_spu->p_sys->pi_alpha[i_color] )
{ {
case 0x00: case 0x00:
...@@ -117,16 +167,27 @@ void E_(RenderSPU)( vout_thread_t *p_vout, picture_t *p_pic, ...@@ -117,16 +167,27 @@ void E_(RenderSPU)( vout_thread_t *p_vout, picture_t *p_pic,
(u16)*p_destptr * i_destalpha ) >> 4; (u16)*p_destptr * i_destalpha ) >> 4;
} }
break; break;
} }
i_x -= i_len;
} }
} }
}
break; static void RenderRV16( vout_thread_t *p_vout, picture_t *p_pic,
const subpicture_t *p_spu, vlc_bool_t b_crop )
{
/* Common variables */
u16 p_clut16[4];
u8 *p_dest;
u16 *p_source = (u16 *)p_spu->p_sys->p_data;
/* RV16 target, scaling */ int i_x, i_y;
case VLC_FOURCC('R','V','1','6'): int i_len, i_color;
/* RGB-specific */
int i_xscale, i_yscale, i_width, i_height, i_ytmp, i_yreal, i_ynext;
/* Crop-specific */
int i_x_start, i_y_start, i_x_end, i_y_end;
/* XXX: this is a COMPLETE HACK, memcpy is unable to do u16s anyway */ /* XXX: this is a COMPLETE HACK, memcpy is unable to do u16s anyway */
/* FIXME: get this from the DVD */ /* FIXME: get this from the DVD */
...@@ -147,6 +208,11 @@ void E_(RenderSPU)( vout_thread_t *p_vout, picture_t *p_pic, ...@@ -147,6 +208,11 @@ void E_(RenderSPU)( vout_thread_t *p_vout, picture_t *p_pic,
+ ( (p_spu->i_x * i_xscale) >> 6 ) * 2 + ( (p_spu->i_x * i_xscale) >> 6 ) * 2
+ ( (p_spu->i_y * i_yscale) >> 6 ) * p_pic->p->i_pitch; + ( (p_spu->i_y * i_yscale) >> 6 ) * p_pic->p->i_pitch;
i_x_start = i_width - i_xscale * p_spu->p_sys->i_x_end;
i_y_start = i_yscale * p_spu->p_sys->i_y_start;
i_x_end = i_width - i_xscale * p_spu->p_sys->i_x_start;
i_y_end = i_yscale * p_spu->p_sys->i_y_end;
/* Draw until we reach the bottom of the subtitle */ /* Draw until we reach the bottom of the subtitle */
for( i_y = 0 ; i_y < i_height ; ) for( i_y = 0 ; i_y < i_height ; )
{ {
...@@ -160,35 +226,37 @@ void E_(RenderSPU)( vout_thread_t *p_vout, picture_t *p_pic, ...@@ -160,35 +226,37 @@ void E_(RenderSPU)( vout_thread_t *p_vout, picture_t *p_pic,
i_yreal = p_pic->p->i_pitch * i_ytmp; i_yreal = p_pic->p->i_pitch * i_ytmp;
/* Draw until we reach the end of the line */ /* Draw until we reach the end of the line */
for( i_x = i_width ; i_x ; ) for( i_x = i_width ; i_x ; i_x -= i_len )
{ {
/* Get the RLE part, then draw the line */ /* Get the RLE part, then draw the line */
i_color = *p_source & 0x3; i_color = *p_source & 0x3;
i_len = i_xscale * ( *p_source++ >> 2 );
if( b_crop
&& ( i_x < i_x_start || i_x > i_x_end
|| i_y < i_y_start || i_y > i_y_end ) )
{
continue;
}
switch( p_spu->p_sys->pi_alpha[ i_color ] ) switch( p_spu->p_sys->pi_alpha[ i_color ] )
{ {
case 0x00: case 0x00:
i_x -= i_xscale * ( *p_source++ >> 2 );
break; break;
case 0x0f: case 0x0f:
i_len = i_xscale * ( *p_source++ >> 2 );
memset( p_dest - 2 * ( i_x >> 6 ) + i_yreal, memset( p_dest - 2 * ( i_x >> 6 ) + i_yreal,
p_clut16[ i_color ], p_clut16[ i_color ],
2 * ( ( i_len >> 6 ) + 1 ) ); 2 * ( ( i_len >> 6 ) + 1 ) );
i_x -= i_len;
break; break;
default: default:
/* FIXME: we should do transparency */ /* FIXME: we should do transparency */
i_len = i_xscale * ( *p_source++ >> 2 );
memset( p_dest - 2 * ( i_x >> 6 ) + i_yreal, memset( p_dest - 2 * ( i_x >> 6 ) + i_yreal,
p_clut16[ i_color ], p_clut16[ i_color ],
2 * ( ( i_len >> 6 ) + 1 ) ); 2 * ( ( i_len >> 6 ) + 1 ) );
i_x -= i_len;
break; break;
} }
} }
} }
else else
...@@ -197,19 +265,25 @@ void E_(RenderSPU)( vout_thread_t *p_vout, picture_t *p_pic, ...@@ -197,19 +265,25 @@ void E_(RenderSPU)( vout_thread_t *p_vout, picture_t *p_pic,
i_ynext = p_pic->p->i_pitch * i_y >> 6; i_ynext = p_pic->p->i_pitch * i_y >> 6;
/* Draw until we reach the end of the line */ /* Draw until we reach the end of the line */
for( i_x = i_width ; i_x ; ) for( i_x = i_width ; i_x ; i_x -= i_len )
{ {
/* Get the RLE part, then draw as many lines as needed */ /* Get the RLE part, then draw as many lines as needed */
i_color = *p_source & 0x3; i_color = *p_source & 0x3;
i_len = i_xscale * ( *p_source++ >> 2 );
if( b_crop
&& ( i_x < i_x_start || i_x > i_x_end
|| i_y < i_y_start || i_y > i_y_end ) )
{
continue;
}
switch( p_spu->p_sys->pi_alpha[ i_color ] ) switch( p_spu->p_sys->pi_alpha[ i_color ] )
{ {
case 0x00: case 0x00:
i_x -= i_xscale * ( *p_source++ >> 2 );
break; break;
case 0x0f: case 0x0f:
i_len = i_xscale * ( *p_source++ >> 2 );
for( i_ytmp = i_yreal ; i_ytmp < i_ynext ; for( i_ytmp = i_yreal ; i_ytmp < i_ynext ;
i_ytmp += p_pic->p->i_pitch ) i_ytmp += p_pic->p->i_pitch )
{ {
...@@ -217,12 +291,10 @@ void E_(RenderSPU)( vout_thread_t *p_vout, picture_t *p_pic, ...@@ -217,12 +291,10 @@ void E_(RenderSPU)( vout_thread_t *p_vout, picture_t *p_pic,
p_clut16[ i_color ], p_clut16[ i_color ],
2 * ( ( i_len >> 6 ) + 1 ) ); 2 * ( ( i_len >> 6 ) + 1 ) );
} }
i_x -= i_len;
break; break;
default: default:
/* FIXME: we should do transparency */ /* FIXME: we should do transparency */
i_len = i_xscale * ( *p_source++ >> 2 );
for( i_ytmp = i_yreal ; i_ytmp < i_ynext ; for( i_ytmp = i_yreal ; i_ytmp < i_ynext ;
i_ytmp += p_pic->p->i_pitch ) i_ytmp += p_pic->p->i_pitch )
{ {
...@@ -230,18 +302,29 @@ void E_(RenderSPU)( vout_thread_t *p_vout, picture_t *p_pic, ...@@ -230,18 +302,29 @@ void E_(RenderSPU)( vout_thread_t *p_vout, picture_t *p_pic,
p_clut16[ i_color ], p_clut16[ i_color ],
2 * ( ( i_len >> 6 ) + 1 ) ); 2 * ( ( i_len >> 6 ) + 1 ) );
} }
i_x -= i_len;
break; break;
} }
} }
} }
} }
}
break; static void RenderRV32( vout_thread_t *p_vout, picture_t *p_pic,
const subpicture_t *p_spu, vlc_bool_t b_crop )
{
/* Common variables */
u32 p_clut32[4];
u8 *p_dest;
u16 *p_source = (u16 *)p_spu->p_sys->p_data;
/* RV32 target, scaling */ int i_x, i_y;
case VLC_FOURCC('R','V','2','4'): int i_len, i_color;
case VLC_FOURCC('R','V','3','2'):
/* RGB-specific */
int i_xscale, i_yscale, i_width, i_height, i_ytmp, i_yreal, i_ynext;
/* Crop-specific */
int i_x_start, i_y_start, i_x_end, i_y_end;
/* XXX: this is a COMPLETE HACK, memcpy is unable to do u32s anyway */ /* XXX: this is a COMPLETE HACK, memcpy is unable to do u32s anyway */
/* FIXME: get this from the DVD */ /* FIXME: get this from the DVD */
...@@ -257,6 +340,11 @@ void E_(RenderSPU)( vout_thread_t *p_vout, picture_t *p_pic, ...@@ -257,6 +340,11 @@ void E_(RenderSPU)( vout_thread_t *p_vout, picture_t *p_pic,
i_width = p_spu->i_width * i_xscale; i_width = p_spu->i_width * i_xscale;
i_height = p_spu->i_height * i_yscale; i_height = p_spu->i_height * i_yscale;
i_x_start = i_width - i_xscale * p_spu->p_sys->i_x_end;
i_y_start = i_yscale * p_spu->p_sys->i_y_start;
i_x_end = i_width - i_xscale * p_spu->p_sys->i_x_start;
i_y_end = i_yscale * p_spu->p_sys->i_y_end;
p_dest = p_pic->p->p_pixels + ( i_width >> 6 ) * 4 p_dest = p_pic->p->p_pixels + ( i_width >> 6 ) * 4
/* Add the picture coordinates and the SPU coordinates */ /* Add the picture coordinates and the SPU coordinates */
+ ( (p_spu->i_x * i_xscale) >> 6 ) * 4 + ( (p_spu->i_x * i_xscale) >> 6 ) * 4
...@@ -275,33 +363,35 @@ void E_(RenderSPU)( vout_thread_t *p_vout, picture_t *p_pic, ...@@ -275,33 +363,35 @@ void E_(RenderSPU)( vout_thread_t *p_vout, picture_t *p_pic,
i_yreal = p_pic->p->i_pitch * i_ytmp; i_yreal = p_pic->p->i_pitch * i_ytmp;
/* Draw until we reach the end of the line */ /* Draw until we reach the end of the line */
for( i_x = i_width ; i_x ; ) for( i_x = i_width ; i_x ; i_x -= i_len )
{ {
/* Get the RLE part, then draw the line */ /* Get the RLE part, then draw the line */
i_color = *p_source & 0x3; i_color = *p_source & 0x3;
i_len = i_xscale * ( *p_source++ >> 2 );
if( b_crop
&& ( i_x < i_x_start || i_x > i_x_end
|| i_y < i_y_start || i_y > i_y_end ) )
{
continue;
}
switch( p_spu->p_sys->pi_alpha[ i_color ] ) switch( p_spu->p_sys->pi_alpha[ i_color ] )
{ {
case 0x00: case 0x00:
i_x -= i_xscale * ( *p_source++ >> 2 );
break; break;
case 0x0f: case 0x0f:
i_len = i_xscale * ( *p_source++ >> 2 );
memset( p_dest - 4 * ( i_x >> 6 ) + i_yreal, memset( p_dest - 4 * ( i_x >> 6 ) + i_yreal,
p_clut32[ i_color ], 4 * ( ( i_len >> 6 ) + 1 ) ); p_clut32[ i_color ], 4 * ( ( i_len >> 6 ) + 1 ) );
i_x -= i_len;
break; break;
default: default:
/* FIXME: we should do transparency */ /* FIXME: we should do transparency */
i_len = i_xscale * ( *p_source++ >> 2 );
memset( p_dest - 4 * ( i_x >> 6 ) + i_yreal, memset( p_dest - 4 * ( i_x >> 6 ) + i_yreal,
p_clut32[ i_color ], 4 * ( ( i_len >> 6 ) + 1 ) ); p_clut32[ i_color ], 4 * ( ( i_len >> 6 ) + 1 ) );
i_x -= i_len;
break; break;
} }
} }
} }
else else
...@@ -310,19 +400,25 @@ void E_(RenderSPU)( vout_thread_t *p_vout, picture_t *p_pic, ...@@ -310,19 +400,25 @@ void E_(RenderSPU)( vout_thread_t *p_vout, picture_t *p_pic,
i_ynext = p_pic->p->i_pitch * i_y >> 6; i_ynext = p_pic->p->i_pitch * i_y >> 6;
/* Draw until we reach the end of the line */ /* Draw until we reach the end of the line */
for( i_x = i_width ; i_x ; ) for( i_x = i_width ; i_x ; i_x -= i_len )
{ {
/* Get the RLE part, then draw as many lines as needed */ /* Get the RLE part, then draw as many lines as needed */
i_color = *p_source & 0x3; i_color = *p_source & 0x3;
i_len = i_xscale * ( *p_source++ >> 2 );
if( b_crop
&& ( i_x < i_x_start || i_x > i_x_end
|| i_y < i_y_start || i_y > i_y_end ) )
{
continue;
}
switch( p_spu->p_sys->pi_alpha[ i_color ] ) switch( p_spu->p_sys->pi_alpha[ i_color ] )
{ {
case 0x00: case 0x00:
i_x -= i_xscale * ( *p_source++ >> 2 );
break; break;
case 0x0f: case 0x0f:
i_len = i_xscale * ( *p_source++ >> 2 );
for( i_ytmp = i_yreal ; i_ytmp < i_ynext ; for( i_ytmp = i_yreal ; i_ytmp < i_ynext ;
i_ytmp += p_pic->p->i_pitch ) i_ytmp += p_pic->p->i_pitch )
{ {
...@@ -330,12 +426,10 @@ void E_(RenderSPU)( vout_thread_t *p_vout, picture_t *p_pic, ...@@ -330,12 +426,10 @@ void E_(RenderSPU)( vout_thread_t *p_vout, picture_t *p_pic,
p_clut32[ i_color ], p_clut32[ i_color ],
4 * ( ( i_len >> 6 ) + 1 ) ); 4 * ( ( i_len >> 6 ) + 1 ) );
} }
i_x -= i_len;
break; break;
default: default:
/* FIXME: we should do transparency */ /* FIXME: we should do transparency */
i_len = i_xscale * ( *p_source++ >> 2 );
for( i_ytmp = i_yreal ; i_ytmp < i_ynext ; for( i_ytmp = i_yreal ; i_ytmp < i_ynext ;
i_ytmp += p_pic->p->i_pitch ) i_ytmp += p_pic->p->i_pitch )
{ {
...@@ -343,40 +437,63 @@ void E_(RenderSPU)( vout_thread_t *p_vout, picture_t *p_pic, ...@@ -343,40 +437,63 @@ void E_(RenderSPU)( vout_thread_t *p_vout, picture_t *p_pic,
p_clut32[ i_color ], p_clut32[ i_color ],
4 * ( ( i_len >> 6 ) + 1 ) ); 4 * ( ( i_len >> 6 ) + 1 ) );
} }
i_x -= i_len;
break; break;
} }
} }
} }
} }
}
static void RenderYUY2( vout_thread_t *p_vout, picture_t *p_pic,
const subpicture_t *p_spu, vlc_bool_t b_crop )
{
/* Common variables */
u8 *p_dest;
u16 *p_source = (u16 *)p_spu->p_sys->p_data;
break; int i_x, i_y;
int i_len, i_color;
u8 i_cnt;
/* NVidia overlay, no scaling */ /* Crop-specific */
case VLC_FOURCC('Y','U','Y','2'): int i_x_start, i_y_start, i_x_end, i_y_end;
p_dest = p_pic->p->p_pixels + p_dest = p_pic->p->p_pixels +
+ ( p_spu->i_y + p_spu->i_height ) * p_pic->p->i_pitch // * bytes per line + ( p_spu->i_y + p_spu->i_height ) * p_pic->p->i_pitch // * bytes per line
+ ( p_spu->i_x + p_spu->i_width ) * 2; // * bytes per pixel + ( p_spu->i_x + p_spu->i_width ) * 2; // * bytes per pixel
i_x_start = p_spu->i_width - p_spu->p_sys->i_x_end;
i_y_start = (p_spu->i_height - p_spu->p_sys->i_y_end)
* p_pic->p->i_pitch / 2;
i_x_end = p_spu->i_width - p_spu->p_sys->i_x_start;
i_y_end = (p_spu->i_height - p_spu->p_sys->i_y_start)
* p_pic->p->i_pitch / 2;
/* Draw until we reach the bottom of the subtitle */ /* Draw until we reach the bottom of the subtitle */
for( i_y = p_spu->i_height * p_pic->p->i_pitch / 2; for( i_y = p_spu->i_height * p_pic->p->i_pitch / 2;
i_y ; i_y ;
i_y -= p_pic->p->i_pitch / 2 ) i_y -= p_pic->p->i_pitch / 2 )
{ {
/* Draw until we reach the end of the line */ /* Draw until we reach the end of the line */
for( i_x = p_spu->i_width ; i_x ; ) for( i_x = p_spu->i_width ; i_x ; i_x -= i_len )
{ {
/* Get the RLE part, then draw the line */ /* Get the RLE part, then draw the line */
i_color = *p_source & 0x3; i_color = *p_source & 0x3;
i_len = *p_source++ >> 2;
if( b_crop
&& ( i_x < i_x_start || i_x > i_x_end
|| i_y < i_y_start || i_y > i_y_end ) )
{
continue;
}
switch( p_spu->p_sys->pi_alpha[ i_color ] ) switch( p_spu->p_sys->pi_alpha[ i_color ] )
{ {
case 0x00: case 0x00:
i_x -= *p_source++ >> 2;
break; break;
case 0x0f: case 0x0f:
i_len = *p_source++ >> 2;
for( i_cnt = 0; i_cnt < i_len; i_cnt++ ) for( i_cnt = 0; i_cnt < i_len; i_cnt++ )
{ {
/* draw a pixel */ /* draw a pixel */
...@@ -393,12 +510,10 @@ void E_(RenderSPU)( vout_thread_t *p_vout, picture_t *p_pic, ...@@ -393,12 +510,10 @@ void E_(RenderSPU)( vout_thread_t *p_vout, picture_t *p_pic,
0x80, 1); 0x80, 1);
} }
} }
i_x -= i_len;
break; break;
default: default:
/* FIXME: we should do transparency */ /* FIXME: we should do transparency */
i_len = *p_source++ >> 2;
for( i_cnt = 0; i_cnt < i_len; i_cnt++ ) for( i_cnt = 0; i_cnt < i_len; i_cnt++ )
{ {
/* draw a pixel */ /* draw a pixel */
...@@ -415,17 +530,9 @@ void E_(RenderSPU)( vout_thread_t *p_vout, picture_t *p_pic, ...@@ -415,17 +530,9 @@ void E_(RenderSPU)( vout_thread_t *p_vout, picture_t *p_pic,
0x80, 1); 0x80, 1);
} }
} }
i_x -= i_len;
break; break;
} }
} }
} }
break;
default:
msg_Err( p_vout, "unknown chroma, can't render SPU" );
break;
}
} }
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* spudec.c : SPU decoder thread * spudec.c : SPU decoder thread
***************************************************************************** *****************************************************************************
* Copyright (C) 2000-2001 VideoLAN * Copyright (C) 2000-2001 VideoLAN
* $Id: spudec.c,v 1.6 2002/10/31 09:40:26 gbazin Exp $ * $Id: spudec.c,v 1.7 2002/11/06 18:07:57 sam Exp $
* *
* Authors: Samuel Hocevar <sam@zoy.org> * Authors: Samuel Hocevar <sam@zoy.org>
* *
...@@ -68,14 +68,15 @@ static int OpenDecoder( vlc_object_t *p_this ) ...@@ -68,14 +68,15 @@ static int OpenDecoder( vlc_object_t *p_this )
{ {
decoder_fifo_t *p_fifo = (decoder_fifo_t*) p_this; decoder_fifo_t *p_fifo = (decoder_fifo_t*) p_this;
if( p_fifo->i_fourcc == VLC_FOURCC('s','p','u',' ') if( p_fifo->i_fourcc != VLC_FOURCC('s','p','u',' ')
|| p_fifo->i_fourcc == VLC_FOURCC('s','p','u','b') ) && p_fifo->i_fourcc != VLC_FOURCC('s','p','u','b') )
{ {
p_fifo->pf_run = RunDecoder; return VLC_EGENERIC;
return VLC_SUCCESS;
} }
return VLC_EGENERIC; p_fifo->pf_run = RunDecoder;
return VLC_SUCCESS;
} }
/***************************************************************************** /*****************************************************************************
...@@ -84,7 +85,7 @@ static int OpenDecoder( vlc_object_t *p_this ) ...@@ -84,7 +85,7 @@ static int OpenDecoder( vlc_object_t *p_this )
static int RunDecoder( decoder_fifo_t * p_fifo ) static int RunDecoder( decoder_fifo_t * p_fifo )
{ {
spudec_thread_t * p_spudec; spudec_thread_t * p_spudec;
/* Allocate the memory needed to store the thread's structure */ /* Allocate the memory needed to store the thread's structure */
p_spudec = (spudec_thread_t *)malloc( sizeof(spudec_thread_t) ); p_spudec = (spudec_thread_t *)malloc( sizeof(spudec_thread_t) );
...@@ -112,10 +113,12 @@ static int RunDecoder( decoder_fifo_t * p_fifo ) ...@@ -112,10 +113,12 @@ static int RunDecoder( decoder_fifo_t * p_fifo )
*/ */
while( (!p_spudec->p_fifo->b_die) && (!p_spudec->p_fifo->b_error) ) while( (!p_spudec->p_fifo->b_die) && (!p_spudec->p_fifo->b_error) )
{ {
if( !E_(SyncPacket)( p_spudec ) ) if( E_(SyncPacket)( p_spudec ) )
{ {
E_(ParsePacket)( p_spudec ); continue;
} }
E_(ParsePacket)( p_spudec );
} }
/* /*
...@@ -183,7 +186,7 @@ static int InitThread( spudec_thread_t *p_spudec ) ...@@ -183,7 +186,7 @@ static int InitThread( spudec_thread_t *p_spudec )
static void EndThread( spudec_thread_t *p_spudec ) static void EndThread( spudec_thread_t *p_spudec )
{ {
if( p_spudec->p_vout != NULL if( p_spudec->p_vout != NULL
&& p_spudec->p_vout->p_subpicture != NULL ) && p_spudec->p_vout->p_subpicture != NULL )
{ {
subpicture_t * p_subpic; subpicture_t * p_subpic;
int i_subpic; int i_subpic;
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* spudec.h : sub picture unit decoder thread interface * spudec.h : sub picture unit decoder thread interface
***************************************************************************** *****************************************************************************
* Copyright (C) 1999, 2000 VideoLAN * Copyright (C) 1999, 2000 VideoLAN
* $Id: spudec.h,v 1.2 2002/08/16 03:07:56 sam Exp $ * $Id: spudec.h,v 1.3 2002/11/06 18:07:57 sam Exp $
* *
* Authors: Samuel Hocevar <sam@zoy.org> * Authors: Samuel Hocevar <sam@zoy.org>
* *
...@@ -21,6 +21,8 @@ ...@@ -21,6 +21,8 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
*****************************************************************************/ *****************************************************************************/
typedef struct spudec_thread_t spudec_thread_t;
struct subpicture_sys_t struct subpicture_sys_t
{ {
mtime_t i_pts; /* presentation timestamp */ mtime_t i_pts; /* presentation timestamp */
...@@ -30,14 +32,22 @@ struct subpicture_sys_t ...@@ -30,14 +32,22 @@ struct subpicture_sys_t
/* Color information */ /* Color information */
vlc_bool_t b_palette; vlc_bool_t b_palette;
u8 pi_alpha[4]; uint8_t pi_alpha[4];
u8 pi_yuv[4][3]; uint8_t pi_yuv[4][3];
/* Link to our input */
vlc_object_t * p_input;
/* Cropping properties */
vlc_mutex_t lock;
vlc_bool_t b_crop;
int i_x_start, i_y_start, i_x_end, i_y_end;
}; };
/***************************************************************************** /*****************************************************************************
* spudec_thread_t : sub picture unit decoder thread descriptor * spudec_thread_t : sub picture unit decoder thread descriptor
*****************************************************************************/ *****************************************************************************/
typedef struct spudec_thread_t struct spudec_thread_t
{ {
/* /*
* Thread properties and locks * Thread properties and locks
...@@ -61,8 +71,7 @@ typedef struct spudec_thread_t ...@@ -61,8 +71,7 @@ typedef struct spudec_thread_t
*/ */
int i_spu_size; /* size of current SPU packet */ int i_spu_size; /* size of current SPU packet */
int i_rle_size; /* size of the RLE part */ int i_rle_size; /* size of the RLE part */
};
} spudec_thread_t;
/***************************************************************************** /*****************************************************************************
* Amount of bytes we GetChunk() in one go * Amount of bytes we GetChunk() in one go
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* vout_subpictures.c : subpicture management functions * vout_subpictures.c : subpicture management functions
***************************************************************************** *****************************************************************************
* Copyright (C) 2000 VideoLAN * Copyright (C) 2000 VideoLAN
* $Id: vout_subpictures.c,v 1.15 2002/10/17 08:24:12 sam Exp $ * $Id: vout_subpictures.c,v 1.16 2002/11/06 18:07:56 sam Exp $
* *
* Authors: Vincent Seguin <seguin@via.ecp.fr> * Authors: Vincent Seguin <seguin@via.ecp.fr>
* Samuel Hocevar <sam@zoy.org> * Samuel Hocevar <sam@zoy.org>
...@@ -77,12 +77,10 @@ void vout_DisplaySubPicture( vout_thread_t *p_vout, subpicture_t *p_subpic ) ...@@ -77,12 +77,10 @@ void vout_DisplaySubPicture( vout_thread_t *p_vout, subpicture_t *p_subpic )
* already allocated zone of memory in the spu data fields. It needs locking * already allocated zone of memory in the spu data fields. It needs locking
* since several pictures can be created by several producers threads. * since several pictures can be created by several producers threads.
*****************************************************************************/ *****************************************************************************/
subpicture_t *vout_CreateSubPicture( vout_thread_t *p_vout, int i_type, subpicture_t *vout_CreateSubPicture( vout_thread_t *p_vout, int i_type )
int i_size )
{ {
int i_subpic; /* subpicture index */ int i_subpic; /* subpicture index */
subpicture_t * p_free_subpic = NULL; /* first free subpicture */ subpicture_t * p_subpic = NULL; /* first free subpicture */
subpicture_t * p_destroyed_subpic = NULL; /* first destroyed subpic */
/* Get lock */ /* Get lock */
vlc_mutex_lock( &p_vout->subpicture_lock ); vlc_mutex_lock( &p_vout->subpicture_lock );
...@@ -92,78 +90,39 @@ subpicture_t *vout_CreateSubPicture( vout_thread_t *p_vout, int i_type, ...@@ -92,78 +90,39 @@ subpicture_t *vout_CreateSubPicture( vout_thread_t *p_vout, int i_type,
*/ */
for( i_subpic = 0; i_subpic < VOUT_MAX_SUBPICTURES; 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( p_vout->p_subpicture[i_subpic].i_status == FREE_SUBPICTURE )
{
/* Subpicture is marked for destruction, but is still allocated */
if( (p_vout->p_subpicture[i_subpic].i_type == i_type) &&
(p_vout->p_subpicture[i_subpic].i_size >= i_size) )
{
/* Memory size do match or is smaller : memory will not be
* reallocated, and function can end immediately - this is
* the best possible case, since no memory allocation needs
* to be done */
p_vout->p_subpicture[i_subpic].i_status = RESERVED_SUBPICTURE;
vlc_mutex_unlock( &p_vout->subpicture_lock );
return &p_vout->p_subpicture[i_subpic];
}
else if( p_destroyed_subpic == NULL )
{
/* Memory size do not match, but subpicture index will be kept
* in case we find no other place */
p_destroyed_subpic = &p_vout->p_subpicture[i_subpic];
}
}
else if( (p_free_subpic == NULL) &&
(p_vout->p_subpicture[i_subpic].i_status == FREE_SUBPICTURE ))
{ {
/* Subpicture is empty and ready for allocation */ /* Subpicture is empty and ready for allocation */
p_free_subpic = &p_vout->p_subpicture[i_subpic]; p_subpic = &p_vout->p_subpicture[i_subpic];
p_vout->p_subpicture[i_subpic].i_status = RESERVED_SUBPICTURE;
break;
} }
} }
/* If no free subpictures are available, use a destroyed subpicture */ /* If no free subpicture could be found */
if( (p_free_subpic == NULL) && (p_destroyed_subpic != NULL ) ) if( p_subpic == NULL )
{
/* No free subpicture or matching destroyed subpictures have been
* found, but a destroyed subpicture is still available */
free( p_destroyed_subpic->p_sys_orig );
p_free_subpic = p_destroyed_subpic;
}
/* If no free or destroyed subpicture could be found */
if( p_free_subpic == NULL )
{ {
msg_Err( p_vout, "subpicture heap is full" ); msg_Err( p_vout, "subpicture heap is full" );
vlc_mutex_unlock( &p_vout->subpicture_lock ); vlc_mutex_unlock( &p_vout->subpicture_lock );
return NULL; return NULL;
} }
p_free_subpic->p_sys = /* Copy subpicture information, set some default values */
vlc_memalign( &p_free_subpic->p_sys_orig, 16, i_size ); p_subpic->i_type = i_type;
p_subpic->i_status = RESERVED_SUBPICTURE;
if( p_free_subpic->p_sys != NULL ) p_subpic->i_start = 0;
{ p_subpic->i_stop = 0;
/* Copy subpicture information, set some default values */ p_subpic->b_ephemer = VLC_FALSE;
p_free_subpic->i_type = i_type;
p_free_subpic->i_status = RESERVED_SUBPICTURE; p_subpic->i_x = 0;
p_free_subpic->i_size = i_size; p_subpic->i_y = 0;
p_free_subpic->i_x = 0; p_subpic->i_width = 0;
p_free_subpic->i_y = 0; p_subpic->i_height = 0;
p_free_subpic->i_width = 0;
p_free_subpic->i_height = 0;
}
else
{
/* Memory allocation failed : set subpicture as empty */
msg_Err( p_vout, "out of memory" );
p_free_subpic->i_type = EMPTY_SUBPICTURE;
p_free_subpic->i_status = FREE_SUBPICTURE;
p_free_subpic = NULL;
}
vlc_mutex_unlock( &p_vout->subpicture_lock ); vlc_mutex_unlock( &p_vout->subpicture_lock );
return p_free_subpic; return p_subpic;
} }
/***************************************************************************** /*****************************************************************************
...@@ -176,15 +135,20 @@ subpicture_t *vout_CreateSubPicture( vout_thread_t *p_vout, int i_type, ...@@ -176,15 +135,20 @@ subpicture_t *vout_CreateSubPicture( vout_thread_t *p_vout, int i_type,
*****************************************************************************/ *****************************************************************************/
void vout_DestroySubPicture( vout_thread_t *p_vout, subpicture_t *p_subpic ) void vout_DestroySubPicture( vout_thread_t *p_vout, subpicture_t *p_subpic )
{ {
/* Check if status is valid */ /* Check if status is valid */
if( ( p_subpic->i_status != RESERVED_SUBPICTURE ) if( ( p_subpic->i_status != RESERVED_SUBPICTURE )
&& ( p_subpic->i_status != READY_SUBPICTURE ) ) && ( p_subpic->i_status != READY_SUBPICTURE ) )
{ {
msg_Err( p_vout, "subpicture %p has invalid status %d", msg_Err( p_vout, "subpicture %p has invalid status %d",
p_subpic, p_subpic->i_status ); p_subpic, p_subpic->i_status );
} }
p_subpic->i_status = DESTROYED_SUBPICTURE; if( p_subpic->pf_destroy )
{
p_subpic->pf_destroy( p_subpic );
}
p_subpic->i_status = FREE_SUBPICTURE;
} }
/***************************************************************************** /*****************************************************************************
......
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